With 32-bit floats, that value and the ones before and after (by decrementing or incrementing the Significand) are approximately
1234.567749
before
1234.567871
1234.567993
after
1234.568115
after that
The value is incrementing by one at the 8th digit, but then skips .5680
. (If rounding instead of truncating, there's no .5678
) So almost eight significant digits, but really only seven.
The difference is with the String
constructor. On AVR, try
void setup() {
Serial.begin(115200);
float myFloat = 0.090650305151939f;
Serial.println(sizeof(myFloat));
Serial.println(String(myFloat, 15));
Serial.println(myFloat, 15);
Serial.println(String(9065.03f / 100000, 15));
Serial.println(9065.03f / 100000, 15);
}
void loop() {}
With Wokwi I get
4
0.090650305000000
0.090650310516357
0.090650305000000
0.090650310516357
The same code with ESP32 all prints the original best-approximate
0.090650305151939
The "not-rounded" on AVR is not the same. It's closer to the number that comes after
0.0906502977
before
0.09065030515
0.0906503126
after
but not quite. More on this later, but at least the difference is past the significant digits. The String
constructor on both boards -- AVR
String::String(float value, unsigned char decimalPlaces)
{
init();
char buf[33];
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
}
and ESP32
String::String(float value, unsigned int decimalPlaces) {
init();
char *buf = (char *)malloc(decimalPlaces + 42);
if (buf) {
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
free(buf);
} else {
*this = "nan";
log_e("No enough memory for the operation.");
}
}
(those are big buffers, but check out the one for double
on ESP32) -- both use dtostrf
; on ESP32 versus on AVR, where apparently it calls dtoa_prf
. Quite different between those two and also Print::print
, which is the same code on AVR and ESP32. But that code uses double
, which is only 32-bit on AVR, so the results deviate.