0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« on: January 28, 2013, 11:04:39 pm » |
In this piece of code: float f, latminutes, longminutes; long latdecCoords, longdecCoords; int latdegrees, longdegrees; //char sLongDecCoords[10], sLatDecCoords[10]; //convert latitude to GPS Decimal format f = atof(latit1); f /= 100.00; latdegrees = (int)f; //isolate degrees latminutes = ((f - (int)f) * 100.0)+(atof(latit2)/10000.00); //get minutes and fraction of minutes latdecCoords = (long)((latminutes / 60.0)*1000000); //convert to fractions of a degree //latdegrees += latdecCoords; //combine it all into one float if(NS[0] == 'S') latdegrees *= -1.0; //cconvert longitude to GPS decimal format f = atof(longit1); f /= 100.00; longdegrees = (int)f; //isolate degrees longminutes = ((f - (int)f) * 100.0) + (atof(longit2)/10000.00); longdecCoords = long((longminutes / 60.0)*1000000); //longdegrees += longdecCoords; if(EW[0] == 'W') longdegrees *= -1.0; sprintf(latitude, "%i.%ld", latdegrees, latdecCoords); sprintf(longitude, "%i.%ld", longdegrees, longdecCoords); Serial.print(longit2); Serial.print(","); Serial.print(atof(longit2)/10000, 4); Serial.print(","); Serial.print(latdegrees); Serial.print(","); Serial.print(latminutes,4); Serial.print(","); Serial.print(longdegrees); Serial.print(","); Serial.println(longminutes,4); and latit1 is equal to "4041" latit2 is equal to "1271" longit1 is equal to "07406" longit2 is equal to "4956" I get an output that looks like this: 4956,0.4956,40,41.1271,-74,6.4954
The problem is longit2. It is equal to "4956" but for some reason after doing this to it: longminutes = ((f - (int)f) * 100.0) + (atof(longit2)/10000.00); the decimal piece ends up being .4954, and this is repeatable.....it is always .0002 off from the expected value. I progressively printed out an evaluation of that statement and it maintains the correct value until I add the arguments in front of the plus sign. What could be going wrong with this? The calculation for latitude works fine....just the longitude is the problem.
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 315
Posts: 35519
Seattle, WA USA
|
 |
« Reply #1 on: January 29, 2013, 05:16:28 am » |
1000000 doesn't look much like an int. 1000000UL does, on the other hand, look like an unsigned long. http://snippets-r-us.com might be able to help you. We can't verify that latit1, latit2, longit1, and longit2 are what you say they are (properly NULL terminated arrays of chars). Intermediate variables, and Serial.print() statements, might help.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« Reply #2 on: January 29, 2013, 10:11:16 am » |
Well I figured out where the problem is but I am not sure how to fix it. To be honest, for this application this level of precision is ridiculous but it still just bugs me that it is coming out like this. Basically, these two lines: f = atof(longit1); Serial.println(f, 4); result in the output: 7406.0000
and f /= 100.00; longdegrees = (int)f; //isolate degrees Serial.println(longdegrees);
results in 74 and longminutes = ((f - (int)f) * 100.0); Serial.println(longminutes,4); results in 5.9998 which is wrong.....it should be 6.0000 based on the original value of f being 7406.0000. Does anyone know why it may be losing .0002 on that value? I don't think I am overrunning any of my datatypes.
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 315
Posts: 35519
Seattle, WA USA
|
 |
« Reply #3 on: January 29, 2013, 10:53:26 am » |
which is wrong.....it should be 6.0000 No. You are performing floating point arithmetic. The 5.9998 value is perfectly reasonable. Print out f to 6 decimal places, after you divide it by 100.0, to see that.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Sr. Member
Karma: 7
Posts: 395
|
 |
« Reply #4 on: January 29, 2013, 10:58:25 am » |
"Working with floating point is like moving piles of sand. Every time you move one you lose a little sand and pick up a little dirt."
|
|
|
|
|
Logged
|
|
|
|
|
Pittsburgh, PA, USA
Offline
Faraday Member
Karma: 31
Posts: 2932
I only know some basic electricity....
|
 |
« Reply #5 on: January 29, 2013, 11:03:30 am » |
Time to look into fixed-point long int or long long int.
Or if you want kilometers to 6 places them work in millimeters and save the decimal point for displays only. That will save you from a lot of work and confusion while keeping the digits exact down to whatever unit you use.
|
|
|
|
|
Logged
|
Examples can be found at Learning in the Main Site and at the Playground
|
|
|
|
0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« Reply #6 on: January 30, 2013, 07:21:59 am » |
which is wrong.....it should be 6.0000 No. You are performing floating point arithmetic. The 5.9998 value is perfectly reasonable. Print out f to 6 decimal places, after you divide it by 100.0, to see that. Ahh.....74.059997. So is there some fix or is this just something we all accept if we insist on working with floating points (and are too lazy to learn fixed point math)?
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 315
Posts: 35519
Seattle, WA USA
|
 |
« Reply #7 on: January 30, 2013, 07:26:17 am » |
So is there some fix Yes. Put the Arduino back in the box, and send it back.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« Reply #8 on: January 30, 2013, 09:45:32 am » |
So is there some fix Yes. Put the Arduino back in the box, and send it back. Ok point taken....no need to be snide 
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
Pittsburgh, PA, USA
Offline
Faraday Member
Karma: 31
Posts: 2932
I only know some basic electricity....
|
 |
« Reply #9 on: January 30, 2013, 10:16:35 am » |
For some things float you can do small rounding but it's been ages since I did that.
|
|
|
|
|
Logged
|
Examples can be found at Learning in the Main Site and at the Playground
|
|
|
|
Left Coast, CA (USA)
Offline
Brattain Member
Karma: 279
Posts: 15314
Measurement changes behavior
|
 |
« Reply #10 on: January 30, 2013, 10:23:55 am » |
"Working with floating point is like moving piles of sand. Every time you move one you lose a little sand and pick up a little dirt."
LOL  OK, this might be a old well known phrase for some, but I've never heard it before and it sums up my experience and limited knowledge of floating point math. My rule is to just say no to FP in a arduino setting unless it's limited to having to receive numbers from some external source that you can not do anything about. Just because the gcc compiler offers some functions, doesn't mean you have to use them or if they are even useful in a arduino environment. Lefty
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Sr. Member
Karma: 7
Posts: 395
|
 |
« Reply #11 on: January 30, 2013, 10:58:45 am » |
I got it from Kernigham and Plauger: "The Elements of Programming Style", first copyrighted in 1974. Most of the examples are in FORTRAN and PL/1! But it is still a great read about, well, programming style. They really pick on Daniel McCracken*.
They actually present the quote as from a "wise programmer". It is easy to find the quote in the book since the index lists "floating point numbers as sandpiles" 8^)
*For those that don't know, anyone who learned FORTRAN in the '70s and '80s probably used a text by McCracken.
|
|
|
|
|
Logged
|
|
|
|
|
Pittsburgh, PA, USA
Offline
Faraday Member
Karma: 31
Posts: 2932
I only know some basic electricity....
|
 |
« Reply #12 on: January 30, 2013, 03:35:10 pm » |
Our FORTRAN book at Drexel had WAT4/WAT5 in the title. Must have been derivative.  Not that I had the $ to stay anyway. Punched the cards, waited for printouts, learned damned little. When I got a TI-56 in Jan 78 I learned more in the 1st month than that semester at Drexel. I learned for example how badly I wanted indirect addressing! LOL! Got that in the TI-59.
|
|
|
|
|
Logged
|
Examples can be found at Learning in the Main Site and at the Playground
|
|
|
|
0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« Reply #13 on: January 30, 2013, 08:26:24 pm » |
Well this works.....basically just got rid of that divide by 100. It looks like this now. Anything that I should be worried about doing it this way? //cconvert longitude to GPS decimal format f = atof(longit1); Serial.println(longit1); longdegrees = (int)(f/100); //isolate degrees Serial.println(longdegrees); longminutes = (f - (longdegrees*100)) + atof(longit2)/10000.00; Serial.println(longit2); Serial.println(longminutes,6); longdecCoords = long((longminutes / 60.0)*1000000UL); if(EW[0] == 'W') longdegrees *= -1.0;
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 315
Posts: 35519
Seattle, WA USA
|
 |
« Reply #14 on: January 31, 2013, 05:30:06 am » |
longdegrees = (int)(f/100); //isolate degrees Serial.println(longdegrees); longminutes = (f - (longdegrees*100)) + atof(longit2)/10000.00; Serial.println(longit2); Serial.println(longminutes,6); longdecCoords = long((longminutes / 60.0)*1000000UL); if(EW[0] == 'W') longdegrees *= -1.0; AFTER you extract data from longdegrees, see if long degrees has the right sign. Fix it, if not. Well, OK. Fine by me.
|
|
|
|
|
Logged
|
|
|
|
|
|