Problem with strtod?

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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:

#include 

#include 
#include 
#include 


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

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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:

double dbl = 0.9258696943694374

as

uint64_t l_long = 9258696943694374;

perhaps? uint64_t can hold up to 18446744073709551615.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There may be potential for someone to port the 64bit code from the avr32-gcc to avr-gcc compiler perhaps?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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?

#include 
#include 

#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;
}

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I compiled your code with gcc-4.3.3 and it worked OK.

C: i = "told you so";