Im having some problems with parsing gps coordinates with the arduino ide.
To be honest I want to process the data without a library.
From my sensor I get this String: 4815.98450
The result of String.toDouble(): 4815.9843750
I also parsed it on my own, but i got the same result: (yes this code is not nice ;))
char buf[10];
msg.toCharArray(buf, 19);
double num = 0.0;
int c;
c = buf[0] - '0';
double num0 = (c * 1000);
c = buf[1] - '0';
double num1 = (c * 100);
c = buf[2] - '0';
double num2 = (c * 10);
c = buf[3] - '0';
double num3 = (c * 1);
c = buf[5] - '0';
double num5 = (c * 0.1);
c = buf[6] - '0';
double num6 = (c * 0.01);
c = buf[7] - '0';
double num7 = (c * 0.001);
c = buf[8] - '0';
double num8 = (c * 0.0001);
c = buf[9] - '0';
double num9 = (c * 0.00001);
num = num + num0;
num = num + num1;
num = num + num2;
num = num + num3;
num = num + num5;
num = num + num6;
num = num + num7;
num = num + num8;
num = num + num9;
Does somebody have a solution for my problems?
Thank you very much :=)
3 Answers 3
There is no easy solution. The Arduino you are using does not support
double precision floating point. The type double
is just an alias for
float
, which has 24-bit accuracy.
Your program is actually giving you the correct result, as the float closest to 4815.98450 is exactly 4815.984375.
-
Thank you for your answer! You helped me a lot because now i know it is no bug. But now im searching for a workaround :)Benjamin_Ellmer– Benjamin_Ellmer2020年05月23日 08:32:14 +00:00Commented May 23, 2020 at 8:32
-
@Benjamin_Ellmer: Maybe store the integer and fractional parts separately?Edgar Bonet– Edgar Bonet2020年05月23日 08:40:08 +00:00Commented May 23, 2020 at 8:40
double
(or float) is just an inappropriate data type.
Perhaps you take int(4815) and float(0.98450) as two numbers?
And BTW, I bet from your sensor you don't get a String object.
-
Im reading the output from the TX of my sensor, so im pretty sure this is a string ;) i figured out that i can do my calculation without the first 2 digits of the number. there are some cases where it does not work but those cases are very unlikelyBenjamin_Ellmer– Benjamin_Ellmer2020年05月24日 18:07:30 +00:00Commented May 24, 2020 at 18:07
You can convert this to a long, do your arithmetic, and convert it back to an ASCII-Decimal number:
Remove the decimal point from the string. Convert the remaining string of digits to a long. Now you have the coordinate in binary, in units of the least significant decimal digit; 1 lsb == 0.00001, if you used 5 decimal places.
Manipulate your data however you need to using long integer arithmetic.
Divide the value by 10^ -(# of fraction digits you used). The quotient is the whole number part; the remainder is the fractional part. Print the quotient and a decimal point. Print the remainder padding with zeros to the left as necessary to result in your printing (# of fraction digits you used) total fraction digits.
The output conversion is even easier if you're willing to use sprintf():
Divide the value by 10^ -(# of fraction digits you used), as above. Let's assume 5 places as in your example:
char buffer[BIGENOUGH+1];
sprintf(buffer, "%ld.%05ld", value/100000, value%100000);
Note that I made two divisions to get the quotient and the remainder and assumed you could tolerate the performance hit. If you're expecting to crank out a lot of values and speed is a factor, you could look up or write a division routine that can return both the quotient and the remainder results from a single division.
Update: @edgar_bonet points out that the compiler is smart enough to notice this fragment uses both results of the numerically same division and avoids dividing twice after all.
-
Re the "routine that can return both the quotient and the remainder results from a single division": this is exactly what avr-gcc does when compiling the example you provided.Edgar Bonet– Edgar Bonet2020年05月23日 17:12:19 +00:00Commented May 23, 2020 at 17:12