BenF:
Single precision (32-bit) float is all you need to do these calculations with a precision and accuracy suitable for any practical purpose. The “trick” is to convert the NMEA GPS coordinates to radians (not decimal degrees). Further, you should calculate distance as an arc rather than a metric value. You will only convert it back to a metric value for display purposes.
Start with reading the NMEA output and convert coordinates to radians. Once you have this working, you can proceed to code for distance calculations.
Some facts:
- Float as implemented on the Arduino is in accordance with IEEE 754. This is single precision (32 bit) float.
- IEEE 754 uses a 23 bit mantissa (determines precision), 8 bits for a two’s complement exponent (determines range) and 1 bit for sign.
- Precision expressed as a number of decimal digits can be calculated from the formula log10(2**24) which is approximately 7.225 decimal digits.
- The float library on Arduino is coded in optimized assembly for the AVR range of micro controllers.
- Using floats for basic arithmetic (multiply, divide, add, subtract) is generally faster on the Arduino than using 32 bit integers, but add somewhat to the initial code size.
What I proposed was 16-bit integer math, not 32 bit. I can't believe float math -- which requires an add-on library -- is faster than 16-bit integer math, which is done through native instructions. In any case, for an individual calculation the difference is going to be microseconds; unless you're tracking millions of devices the difference is going to be immaterial.
Converting to radians does nothing to improve your precision. You start with degrees anyway and then multiply and divide which introduce additional rounding errors. It makes no difference that degrees are 3-digit decimal numbers and radians are 1-digit, the internal representation is base-2.
Here's an experiment: take the measurement given, 121°35'.87663. In excel, convert it to radians, and at every step round your result to seven significant digits. Then convert it back to degrees, also rounding at every step. When I do that I get 121°35'.87400. Three significant digits were lost in the conversion.
With a float, you've got 23 bits of precision. Is that enough?
As a float, you are representing a value with a 23-bit binary times a multiplier. Your precision is determined by the incremental change when the lowest order bit flips. It's the circumference of the earth divided by 2^23. That's about 15 feet. Regardless of what units you pick, that's the smallest increment that can be measured. Unless you are very careful rounding errors can creep in and make your precision significantly worse.
What it really gets down to is precision vs accuracy. The string you get reports a measurement in minutes with five decimal places. This level of precision implies the measurement is accurate to 1/100,000 of a minute. A degree of minute is roughly 1.1 miles; 1/100,000 of a minute is about one half inch. By using integers you maintain that precision. I agree that this precision is greater than the accuracy of the GPS.
Is float precision enough? You tell me. It's probably close to the accuracy of the measurement. I know if it was me I'd rather design in greater precision than lesser, and design to preserve the precision I was given rather than lessen it.