| Author |
Message |
|
|
Posted: Apr 30, 2012 - 01:26 AM |
|


Joined: May 11, 2004
Posts: 152
Location: Canberra Australia
|
|
I am having a problem using the strtod function on a UC3A0. I am pulling a string from a text file that I then need to convert to a double using strtod. I have produced a short demo program to show what is happening that I have built with optimisation turned off. I am just testing this code in the simulator, but in my real program on the silicon I get the same results. Here is my sample code:
Code:
#include <avr32/io.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
double dbl;
char szTmp[80];
dbl = 0.9258696943694374; // TRUNCATED - dbl == 0.925869694369437 after execution
strcpy(szTmp, "0.925869694369437");
dbl = strtod(szTmp, NULL); // CORRECT - dbl == 0.925869694369437 after execution
strcpy(szTmp, "0.9258696943694374");
dbl = strtod(szTmp, NULL); // INCORRECT - dbl == 250.527019545547 after execution
while(1);
}
Basically the problem is when I try to convert a string with 16 significant places strtod produces a completely incorrect result. In the simulator the second call takes a lot longer to execute (about 0.5sec for the first call and about 7sec for the second call).
The number I am trying to convert came from some javascript code that gives 16 significant digits. As a work around I am truncating the string of its last digit before calling strtod, but I would like to understand why this is happening.
Cheers
Simon |
|
|
| |
|
|
|
|
|
Posted: Apr 30, 2012 - 02:36 AM |
|

Joined: Mar 09, 2012
Posts: 1452
Location: North Carolina, USA
|
|
| Most likely, you're pushing the limit of precision. If memory serves me, double has a limit of approximately 16 significant digits, i.e. 16 digits or less depending on the value. |
|
|
| |
|
|
|
|
|
Posted: Apr 30, 2012 - 09:29 AM |
|


Joined: Jul 18, 2005
Posts: 62299
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
If memory serves me, double has a limit of approximately 16 significant digits, i.e. 16 digits or less depending on the value.
That's true on "big computers" where "float" is 32bit IEEE754 and "double" is 64bit IEEE754. The first holds about 7.5 digits of accuracy and the second about 15..16 digits. But on avr-gcc float==double (that is they are both the 32 bit implementation) so you cannot expect to hold more than 7.5 digits
To OP, there are two AVR compilers with 64bit IEEE754 support. One is the $3,000 IAR compiler and the other is the $800 (is it?) "Pro" version of Imagecraft.
From time to time there's been talk of 64bit being added for "double" in avr-gcc but until someone steps up to the plate that remains a pipe dream.
avr-gcc does have uint64_t support so it may be possible to hold more digits of accuracy using integers if the number range fits.
For example hold:
Code:
double dbl = 0.9258696943694374
as
Code:
uint64_t l_long = 9258696943694374;
perhaps? uint64_t can hold up to 18446744073709551615. |
_________________
|
| |
|
|
|
|
|
Posted: Apr 30, 2012 - 09:51 AM |
|


Joined: May 11, 2004
Posts: 152
Location: Canberra Australia
|
|
Yes, I agree I am pushing the limit of a double.
On the AVR32's using AS5.1 a double is in fact 8 bytes (64 bits). That is why I can get a precision of 15 digits in my sample code and it works just fine. Add a 16th digit and strtod magically breaks and gives a very strange result. |
_________________ Simon
http://makin-things.com/
|
| |
|
|
|
|
|
Posted: Apr 30, 2012 - 10:18 AM |
|


Joined: Jul 18, 2005
Posts: 62299
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| There may be potential for someone to port the 64bit code from the avr32-gcc to avr-gcc compiler perhaps? |
_________________
|
| |
|
|
|
|
|
Posted: Apr 30, 2012 - 01:15 PM |
|


Joined: Dec 21, 2006
Posts: 1483
Location: Saar-Lor-Lux
|
|
You are not using the last value of dbl. Maybe you are just folled by wrong/inexact debugging information?
Does code like the following pass or hit abort?
Code:
#include <stdlib.h>
#include <string.h>
#define AT __attribute__((noinline,noclone))
#define VAL "0.9258696943694374"
double AT test1 (void)
{
double dbl;
char szTmp[80];
strcpy (szTmp, VAL);
dbl = strtod (szTmp, NULL);
return dbl;
}
double AT test1b (void)
{
double dbl;
static char szTmp[80];
strcpy (szTmp, VAL);
dbl = strtod (szTmp, NULL);
return dbl;
}
double AT test2 (void)
{
return strtod (VAL, NULL);
}
int AT test3 (void)
{
return strtod (VAL, NULL) > 1.0;
}
int main (void)
{
if (test1() > 1.0)
abort();
if (test1b() > 1.0)
abort();
if (test2() > 1.0)
abort();
if (test3())
abort();
exit (0);
return 0;
}
|
|
|
| |
|
|
|
|
|
Posted: Apr 30, 2012 - 03:30 PM |
|

Joined: Nov 17, 2004
Posts: 13840
Location: Vancouver, BC
|
|
|
Quote:
On the AVR32's
Which means that this is the wrong forum for this post. This is an 8 bit AVR forum. |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Apr 30, 2012 - 03:44 PM |
|


Joined: Jul 10, 2006
Posts: 2655
Location: Minneapolis
|
|
| I compiled your code with gcc-4.3.3 and it worked OK. |
|
|
| |
|
|
|
|
|