ArduinoCore-sam icon indicating copy to clipboard operation
ArduinoCore-sam copied to clipboard

Serial.print causes ovf when printing doubles > 10 decimal digits (Due)

Open tofrnr opened this issue 7 years ago • 11 comments

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

tofrnr avatar Sep 11 '17 21:09 tofrnr

Это особенность библиотеки, так как при выводе числа целая часть конвертируется в uint32_t

It is a feature of the library since the conclusion of the number the integer part is converted to uint32_t

VASilaev avatar Sep 25 '17 04:09 VASilaev

I ssumed that actually already, and if so, then it's a Serial library bug. Nonetheless, by no means a feature though.

tofrnr avatar Sep 25 '17 07:09 tofrnr

Большие числа редко нужны для большенства пользователей. текущая реализация 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

VASilaev avatar Sep 25 '17 08:09 VASilaev

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.

tofrnr avatar Sep 25 '17 09:09 tofrnr

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?)

cousteaulecommandant avatar Dec 25 '17 17:12 cousteaulecommandant

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.

tofrnr avatar Dec 26 '17 16:12 tofrnr

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 ( '_' = ): _20.550

This way, you can have buffer as big as You need. I hope it helped.

Sawiq avatar Mar 04 '19 23:03 Sawiq

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)

tofrnr avatar Mar 05 '19 08:03 tofrnr

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

ggrevera avatar May 30 '19 13:05 ggrevera

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

ggrevera avatar May 30 '19 18:05 ggrevera

Sorry. Take out \n above.

ggrevera avatar May 30 '19 18:05 ggrevera