Go float64 does not work for latitude and longitude

4.7k views Asked by At

I'm trying to parse latitude and longitude from a json object with precision, and I picked float64 for the job. However float64 is somehow rounding the number and I'm not sure what to do in order to avoid rounding.

I've created a quick snippet so you can execute the problem: http://play.golang.org/p/9g6Imn-7GK

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type Position struct {
    Lat float64 `json:"lat"`
    Lon float64 `json:"lon"`
}

func main() {
    s := `{"lat":13.519004709972312,"lon": -13.519004709972312}`
    pos := Position{}
    json.Unmarshal([]byte(s), &pos)

    if !reflect.DeepEqual(s, &pos) {
        fmt.Printf("\nExpected %#v\nbut got  %#v", s, pos)
    }
}
1

There are 1 answers

2
Ezra On BEST ANSWER

A practical solution:

Do nothing.

The difference in the numbers is about a tenth of the width of a single small atom, and your measurements can't possibly be that precise.

The eighth decimal place (you have 15 in your numbers) represents a distance of about 1.1mm. I doubt if your measurements are accurate to this degree, and anything more is getting really silly. The 5th decimal place is about 1.1m, which is in the realm of sanity, and not affected by floating point errors.

The wikipedia page on Decimal Degrees may be helpful in determining which values are reasonable for your project.

Some considerations:

There are two potential issues at play:

  1. Floating point:

    Some reading that might shed light on floating point issues:

    If you read these, and understand how floating point works in practice, you may be enlightened, and understand what's happening and how to work around it.

  2. Precision of measurement:

    This, in my opinion, is the bigger issue. One number you posted was 13.519004709972312, which was displayed as 13.519004709972313. Whether the value has "changed" or not (see: 1), every software calculator I tried to calculate the difference between these values returned 0, which is indicative.

    Doing the calculation by hand revealed a difference of 0.000000000000001 in the values. That is, a 14 zeroes before the trailing one, or 1^-15.

    The wikipedia page on Latitude says:

    the meridian length of 1 degree of latitude on the sphere is 111.2 km.

    Working backward from this, the difference in locations represented by the 15th decimal place in a latitude corresponds to a distance of approximately 0.00000011mm, or 0.11nanometers.

    From the The Physics Factbook's Diameter of an Atom page:

    An atom is a million times smaller than the thickest human hair. The diameter of an atom ranges from about 0.1 to 0.5 nanometers

    Therefore, your measurement would be "off" by at most 1/10 of the diameter of a single atom.

    Even if all my calculations were off by a million or billion times, the distances would still be so small that they would not matter in practice!