2
\$\begingroup\$

I want to store WGS84-coordinates in two integers for latitude and longitude instead of floats to get a higher precision than with floats.

Here's my code:

struct Coordinate
{
    private int latitude;
    private int longitude;

    const double latMin = -90.0f;
    const double latMax = 90.0f;
    const double lngMin = -180.0f;
    const double lngMax = 180.0f;

    public Coordinate(double latitude, double longitude)
    {
        this.latitude = mapDoubleToInt(latitude, latMin, latMax);
        this.longitude = mapDoubleToInt(longitude, lngMin, lngMax);
    }

    public double Latitude { get { return mapIntToDouble(latitude, latMin, latMax); } }
    public double Longitude { get { return mapIntToDouble(longitude, lngMin, lngMax); } }

    private static int mapDoubleToInt(double value, double min, double max)
    {
        return (int)(((long)int.MaxValue - int.MinValue) * (value - min) / (max - min) + int.MinValue);
    }

    private static double mapIntToDouble(int value, double min, double max)
    {
        return ((double)value - int.MinValue) / ((long)int.MaxValue - int.MinValue) * (max - min) + min;
    }   
}

I'm not sure if there is a better to convert the data. There are a lot of casts and arithmetic operations in it -- any way to do this more elegantly?

\$\endgroup\$
  • \$\begingroup\$ You are using double not float. If you want more precision just use decimal. \$\endgroup\$ – paparazzo Jul 16 '17 at 9:00
  • \$\begingroup\$ Decimals are horribly slow. :-( \$\endgroup\$ – user2033412 Jul 16 '17 at 16:13
  • \$\begingroup\$ Decimal are not that much slow than double and you are going through a lot of effort here. You are going to need to cast a lot of the ints to decimal to not get integer math. \$\endgroup\$ – paparazzo Jul 16 '17 at 16:27
  • \$\begingroup\$ But decimal takes 12 bytes! I can't afford that. Otherwise I would use doubles straight away, but I can't even afford those eight bytes. \$\endgroup\$ – user2033412 Jul 16 '17 at 17:19
  • \$\begingroup\$ You should add that to the question \$\endgroup\$ – paparazzo Jul 16 '17 at 18:23
5
\$\begingroup\$

you can avoid stuffing everything in a one-liner:

private static int mapDoubleToInt(double value, double min, double max)
{
    long intRange = 1L << 32; // ==((long)int.MaxValue - int.MinValue)
    double inputRange = max - min;
    return (int)(intRange * (value - min) / inputRange + int.MinValue);
}

private static double mapIntToDouble(int value, double min, double max)
{
    long intRange = 1L << 32; // ==((long)int.MaxValue - int.MinValue)
    double inputRange = max - min;
    return inputRange * ((double)value - int.MinValue) / intRange + min;
} 

After reordering the operations it's now clearer that they are opposites. Especially after extracting the range as variables.

\$\endgroup\$
  • 1
    \$\begingroup\$ The recommendation on type suffixes are to use capitals so as not to confuse l with 1. Suggest using 1L instead. \$\endgroup\$ – Rick Davin Jul 13 '17 at 18:18
  • \$\begingroup\$ Is (1L << 32) really what I want as range or is it ((1L << 32) - 1)? \$\endgroup\$ – user2033412 Jul 14 '17 at 9:52
  • \$\begingroup\$ @user2033412 depends on whether max is inclusive or exclusive. \$\endgroup\$ – ratchet freak Jul 14 '17 at 9:55
  • \$\begingroup\$ It's WGS84 coordinates -- I could make it exclusive by replacing +180° ⇒ −180°, you're right. \$\endgroup\$ – user2033412 Jul 14 '17 at 9:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.