Why does atof() only go out to 2 decimal places?

I was just wondering why atof() only seems to return a number a number out to 2 decimal places? Is there a way to make it to go out to say 4 or 5 decimal places?

Floating point numbers are not about “decimal places.” They are about “significant digits.” See, for example, http://en.wikipedia.org/wiki/Floating_point

Floating point numbers with avr-gcc have six or seven significant decimal digits. The atof() function converts a C-style “string” to the nearest floating point number that can be represented in the computer with this compiler.

Standard C and C++ libraries support printing with scientific notation that shows a specified number of significant decimal digits ("%e" format specifier for C printf() and scientific mode with setprecision() for C++ << output), but, unfortunately, the print functions supplied with Arduino are aimed only at printing a certain number of decimal places.

void setup()
{
    Serial.begin(9600);
}
void loop()
{
    char *pi_str = "3.14159";
    char *x_str = "0.00000314159";
    float pi;
    float x;

    pi = atof(pi_str);
    Serial.print("Pi = ");
    Serial.println(pi, 5); // Show five digits after the decimal point
    x = atof(x_str);
    Serial.print("x  = ");
    Serial.println(x, 11); // Show eleven digits after the decimal point
    delay(5000);
}

Output:


Pi = 3.14159
x  = 0.00000314159

Both Pi and x are represented with six significant decimal digits. Pi shows us six decimal places and x shows 11.

You can specify as many decimal place digits as you want to in the Serial.print statements, and it will print as many as you tell it.

Try the above sketch but use Serial.print(Pi,16) and Serial.print(x,16). It shows lots of digits. Nevertheless, only six or seven significant decimal digits can represent a floating point number stored with avr-gcc. See Footnote.

Regards,

Dave

Footnote:
“There is a difference between 16 decimal digits and 16 correct decimal digits.”
—davekw7x

HMMMM interesting...

I cut and paste your exact code and the output I get is:

Pi = 3 x = 0

I'm using version 017 on a 328 Duem.

If Serial.print is limiting the number of decimal places printing the number then is serial.print also responsible for rounding the numbers. The float numbers are definitely getting rounded.

I cut and paste your exact code

That's why I posted a complete, tested sketch: So that there would be no ambiguity about how I am actually getting the results.

I'm using version 017

Being a newcomer to Arduino, I have no experience with, or knowledge of, previous versions. It seems that I should have mentioned that I am using arduino-0018.

The float numbers are definitely getting rounded.

Yes, they are. If you change it to print pi to three decimal places you get 3.142

Regards,

Dave

I was just wondering why atof() only seems to return a number a number out to 2 decimal places?

I was just wondering how you determined this.

I'm using version 017

As of 0018, "print" and "println" with floating types allow you to specify how many digits you want printing.

Serial.println(pi, 5);

I guess I should read the release notes. Apparently this is a new feature to 018. Thanks for the help.

0018 - 2010.01.29

[core / libraries]

  • Added tone() and noTone() functions for frequency generation.
  • Added Serial.end() command.
    * Added precision parameter for printing of floats / doubles.
  • Incorporated latest version of Firmata.
  • Fixed bug w/ disabling use of the RW pin in the LiquidCrystal library.
  • No longer disabling interrupts in delayMicroseconds().
  • Fixed bug w/ micros() returning incorrect values from within an interrupt.
  • Fixed bug that broke use of analog inputs 8-15 on the Mega.

As of 0018, "print" and "println" with floating types allow you to specify how many digits you want printing.

Thanks AWOL!! This works on the LCD displays too. I was able to get 3 digits of resolution out of the LCD display instead of the two that it defaults to without the lcd.print(PinVoltage,3);in there.

   int sensorValue = analogRead(2); // Reads analog test pin value and stores it for conversion
// Calibration
   float PinVoltage = sensorValue *.0048; // Adjust multiplied value for Calibration. Converts test pin 'int' value to voltage 'float' providing decimal place capabilities
   lcd.setCursor(8,1); // set to bottom line 8th place to put this 'Measured Value' under 'Nominal Value'
   lcd.print(PinVoltage,3); // displays voltage value for 3 digits after decimal place command 'lcd.println(PinVoltage,3)' also works
   lcd.setCursor(13,1); // set to bottom line 13th place holder to display 'Units'
   lcd.print("VDC");  // adds unit of measure to pin voltage, ex: VDC VAC mA dB etc..
   lcd.setCursor(0,1); // set to first character bottom line