ArduinoCore-sam
ArduinoCore-sam copied to clipboard
Serial.print causes ovf when printing doubles > 10 decimal digits (Due)
Serial.print causes ovf when printing doubles > 10 decimal digits (Due) (AVR not tested but probably similar)
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
char str[30];
double f1=1234567.66;
double f2=12345678.66;
double f3=123456789.66;
double f4=1234567890.66;
double f5=12345678901.66;
Serial.println( f1 );
Serial.println( f2 );
Serial.println( f3 );
Serial.println( f4 );
Serial.println( f5 );
sprintf(str, "%.2f", f5 );
Serial.println(str);
}
void loop() {
// put your main code here, to run repeatedly:
}
output:
1234567.66 12345678.66 123456789.66 1234567890.66 ovf 12345678901.66
Это особенность библиотеки, так как при выводе числа целая часть конвертируется в uint32_t
It is a feature of the library since the conclusion of the number the integer part is converted to uint32_t
I ssumed that actually already, and if so, then it's a Serial library bug. Nonetheless, by no means a feature though.
Большие числа редко нужны для большенства пользователей. текущая реализация printFloat оптимизирована для экономии памяти. если Вам нужны большие числа можно использовать dtostrf из <stdlib.h>, которую нужно поместить в printFloat файла print.cpp
Large numbers are rarely needed for most users. The current implementation of printFloat is optimized to save memory. if you need large numbers you can use dtostrf from <stdlib.h>, which you need to put in the printFloat file print.cpp
a faulty result is a faulty result is a faulty result - irrelevant if it's rarely needed or not, and the Due is a 32bit µC capable of 64bit double and 64bit long long. (BTW, the same it's about round() and ceil() and floor() of large numbers, and for sprintf() for formatting floats.)
And finally this is an issue report to the developers to fix that bug, not for starting a discussion among end users like in forums.
Print::printFloat()
is a simple and rather naïve function. The way it is implemented, float printing first converts the number to unsigned long
and then prints it, followed by the fractional part. If the number is larger than 2^32 then it just prints "ovf". See https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/Print.cpp#L223
Personally I don't think this will be changed since Serial.print()
is meant as a simplified function; also, "ovf" does not mean that it overflows a double, it's just a thing Arduino made up to represent that the number overflows whatever the underlying implementation has, so it's technically not "a faulty result". For a more powerful handle of number formatting I would just use printf. PR arduino/Arduino#5938 suggests adding a Serial.printf()
function; maybe that's the way to go if you want a fully functioning printf. (Could we merge that request, please?)
tbh, it does not interest me if there are simple and rather naïve functions, in case they simply work faulty. If a simple and rather naïve function works faulty, it simply has to be corrected. The Arduino API function support SAM and SAMD cpus feat. 64bit double, so Serial.print has to be able to print 64bit double. In the reported issue, it must be able to print 12345678901.66 correctly as 12345678901.66, instead of throwing out a "ovf", period.
Dear all,
I would advise to use AVR stdlib function dtostrf
:
char * dtostrf(
double __val,
signed char __width,
unsigned char __prec,
char * __s)
where: __val - value to be converted; __width - number of all characters written, including sign and leading spaces; __prec - number of decimal places; __s - string buffer, need to be declared beforehand. Returns pointer to __s.
Example:
double val = 20.55;
char* s[8];
String.println(dtostrf(val, 7, 3, s));
Prints out ( '_' =
This way, you can have buffer as big as You need. I hope it helped.
hello, my thread opening issue report was not about workaraounds, my post was about a bug in the Serial.prinf function to "large" 64bit double. If I wanted a workaraound, I would prefer sprintf(). But I expect 64bit doubles to be printed also correctly by the standard Serial.print() function, not throwing an overflow exception. So @ Arduino developers and contributors: Please kindly fix that bug! 8)
Greeting.
I have experienced the same problem when using the Arduino environment, an esp32, and google's firebase timestamps. Timestamps are huge integers (> 32 bit ints but less than 64-bit doubles or 64-bit long longs). So I put the values in a double and then do Serial.print or println and always get ovf.
Since memory usage may be a concern, I'll try replacing it with alternatives and see what happens. Then I'll report back with some potential fixes. (I'll also check longs vs. ints vs. long longs as well.)
George
I replaced all of the 35 lines of code (esp32 version) in Print::printFloat in Print.cpp with the following:
char buff[ 32 ]; sprintf( buff, "%.*f", digits, number ); printf( "%s\n", buff ); return strlen( buff );
This new code works correctly (i.e., does not print ovf). With regard to memory consumption, the new version uses an additional 72 bytes. I think that is a fair trade off for the correct answer (but you may disagree).
I would be happy to contribute this fix to the codebase if someone would be kind enough to guide me. But I am unsure as to how to go about the process, and I've only tested it on an esp32. I'm familiar with git from the command line (but not GitHub).
George
Sorry. Take out \n above.