floating-pointc-stringsatof

Strange behavior with atof


I have an Arduino which receives a message from my smartphone (over bluetooth) containing the unix timestamp. Now, i am trying to sync my DS1307 with that timestamp.

However, it did not work, hence, i begun searching and found some strange behavior upon converting the C-style array containing the timestamp to a float number.

// Copy the time into "timeBuff"
int timeLength = siz - _CAT_LENGTH_;
char timeBuff[timeLength+1];
memcpy(timeBuff, &msg[_CAT_LENGTH_], timeLength);
timeBuff[timeLength] = '\0';

// For debugging
Serial.print(F("timeBuff:   "));
Serial.println(timeBuff);

// Convert timeBuff string into a variable of type long
float deviceTime = atof(timeBuff);

// Now, deviceTime != what we printed above
Serial.print(F("Epoch time: "));
Serial.println(deviceTime);

The first 5 lines copy the right part of the message into a character array, and adds the termination zero.

Afterwards, we print the content of timeBuff and convert it to a float which is stored in deviceTime. Finally, we print deviceTime.

This was the result of my first test

timeBuff:   1476113620
Epoch time: 1476113664.00

And this of the second test

timeBuff:   1476115510
Epoch time: 1476115456.00

Why does the result of atof differ from the string we passed it?


Solution

  • On most platforms float is represented in IEEE-754 single-precision format, which is 32-bit floating point format with 24-bit (23+1) significand. It simply does not have enough precision to represent your numbers. Your numbers require about 32 bits to represent. Integer values wider than 24 bits will generally lose precision when stored in float.

    The loss of precision will manifest itself as loss of trailing bits with rounding in the last remaining bit

    1476113620 -> ‭01010111111110111011010011010100‬
    1476113664 -> ‭01010111111110111011010100000000‬