# loss of precission

When i am trying to convert the coordinates, there is a big loss of precission... please tell me what to do... coordinates in ddmm.mmmm : 2240.2027, 7552.6356 expected coordinates in dd.dddddd : 22.670045, 75.877246 what i am getting : 22.67, 75.88

String lat = "2240.2027";
float floatLat=0;
String lng = "7552.6356";
float floatLng=0;
String test ="";

convert()
{
test=lat;
int ddlat=0;
int mmlat=0;
int mmmmlat=0;
test=test.substring(0,2);
ddlat=test.toInt();
test=lat;
test=test.substring(2,4);
mmlat=test.toInt();
test=lat;
test=test.substring(5,9);
mmmmlat=test.toInt();
floatLat=(mmlat+(mmmmlat*0.0001));
floatLat=floatLat/60;
floatLat=floatLat+ddlat;

test=lng;
test=test.substring(0,2);
ddlat=test.toInt();
test=lng;
test=test.substring(2,4);
mmlat=test.toInt();
test=lng;
test=test.substring(5,9);
mmmmlat=test.toInt();
floatLng=(mmlat+(mmmmlat*0.0001));
floatLng=floatLng/60;
floatLng=floatLng+ddlat;
}

From what I have read the Arduino floating-point math is only good for 6 or 7 digits.

Using an 'unsigned long' type (32 bits) you can get about 9.5 digits of range. That should let you calculate in millionths of a degree.

Please post the whole code - or at least something that compiles without error:

sketch_oct17a:6: error: ISO C++ forbids declaration of ‘convert’ with no type

nkanade: When i am trying to convert the coordinates, there is a big loss of precission... please tell me what to do... coordinates in ddmm.mmmm : 2240.2027, 7552.6356 expected coordinates in dd.dddddd : 22.670045, 75.877246 what i am getting : 22.67, 75.88

You haven't posted the whole code, so I can't tell what your sketch does. What evidence do you have that the result has poor precision? If you're formatting it via the Serial object, I think you'll find that automatically rounds float values to two decimal places and does not print the exact number given to it.

It always helps to read the specification carefully - look for 'optional second parameter': http://www.arduino.cc/en/Serial/Print

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

String inputString = "";         // a string to hold incoming data
String test = "";
String ggaString = "";
String vtgString = "";
boolean stringComplete = false;  // whether the string is complete
boolean gotVtgData = false;
String utcTime = "";
float floatUtcTime=0;
String lat = "";
float floatLat=0;
String lng = "";
float floatLng=0;

void setup() {

Serial.begin(9600);
lcd.begin(16, 2);
inputString.reserve(200);
}

void loop() {

if (stringComplete) {

inputString = "";
stringComplete = false;
}
{
utcTime=ggaString.substring(7,16);
lcd.print("Time : ");
lcd.print(utcTime);
delay(1000);
lcd.clear();
lat=ggaString.substring(18,27);
lcd.print("Lat  : ");
lcd.print(lat);
delay(1000);
lcd.clear();
lng=ggaString.substring(31,40);
lcd.print("Lng  : ");
lcd.print(lng);
delay(1000);
lcd.clear();
convert();

}

}

void convert()
{
test=lat;
int ddlat=0;
int mmlat=0;
int mmmmlat=0;
test=test.substring(0,2);
ddlat=test.toInt();
test=lat;
test=test.substring(2,4);
mmlat=test.toInt();
test=lat;
test=test.substring(5,9);
mmmmlat=test.toInt();
floatLat=(mmlat+(mmmmlat*0.0001));
floatLat=floatLat/60;
floatLat=floatLat+ddlat;

test=lng;
test=test.substring(0,2);
ddlat=test.toInt();
test=lng;
test=test.substring(2,4);
mmlat=test.toInt();
test=lng;
test=test.substring(5,9);
mmmmlat=test.toInt();
floatLng=(mmlat+(mmmmlat*0.0001));
floatLng=floatLng/60;
floatLng=floatLng+ddlat;
}

void serialEvent()

{
while (Serial.available())
{
inputString += inChar;

if (inChar == '\n')
{
test=inputString.substring(0,6);
if(test=="\$GPVTG")
{ vtgString=inputString; gotVtgData= true;}
else if(test=="\$GPGGA")

stringComplete = true;

}

}
}

i want to design an odometer using GPS... the data coming from GPS modules is in form of strings...the format of coordinates is ddmm.mmmm In order to calculate the distance b/w 2 coordinates, we use haversine fomula... this formula requires coordinates in form dd.dddddddd so i first need to convert string into float then convert it into dd.ddddddd form.... the above code gives me coordinates as dd.dd i need more precision in my project

Maybe you could just drop the first 4 digits (DD.dd), after all for an odometer they will be the same anyway. (i.e., instead of using 83.4212121212, always use 1.2121212e-4.

but in haversine formula we need to put complete coordinates…

it is calculated as :

dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
c = 2 * atan2( sqrt(a), sqrt(1-a) )
d = R * c (where R is the radius of the Earth)

Note, double and long double are treated the same as float in the AVR/arduino environment. This means you only have 6 digits or so of precision.

Also note, if you are making very heavy use of floating point, that you might want to consider using another machine that has floating point in hardware. On arduino systems, floating point is all done by emulation routines.

Note that the dlon calculation already does what I suggested. 8^)

A chip like this might be helpful:

It will even parse the NMEA strings.

the above code gives me coordinates as dd.dd

In what way does it give you dd.dd? Where is this value output? Which part of your code actually formats the value output there?

nkanade: d = R * c (where R is the radius of the Earth)

Slight issue here, the earth is not a sphere. However the error in radius from the mean is at most 0.25% which is fit for most purposes.

Also, beware that in floating-point math, another phenomenon often shows up known as "Loss of significance". Wikipedia has a page describing it. I can't tell with a quick look if your formula will suffere from it, but you may want to look into it.

Basically, it's a problem that arises when you subtract a number from another number of similar magnitude, then multiply it, or square it etc. All of the significant digits get lost in the subtraction, then you multiply the remaining insignificant digits by some meaningful value. The result is just amplified noise, and can be completely meaningless.

I usually perform a check anytime I perform a subtraction (if the result is to be used for other operations). If the difference is less than some percentage of either (or both) of the first two values, then you have to force it to zero. (And do a check for a divide-by-zero if your next step divides.)

There are probably other ways to avoid this problem for specific purposes as well.