From f762721603489a0f1741604a71835620253f6c43 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 9 Feb 2020 09:11:41 -0800 Subject: [PATCH] Use sprintf to output floats in Print/dtostrf Fixes #7043 Two slightly different custom routines were implemented by hand in dtostrf (an AVR-lib non-ISO function) and Print. This resulted in inconsistent output of float/double vars when rounding was needed. Replace them all with a call to sprintf(), removing the duplicated, not quite correct code. Print(String(float)) and Print(float) now generate the same output. --- cores/esp8266/Print.cpp | 45 +---------------- cores/esp8266/Print.h | 2 + cores/esp8266/core_esp8266_noniso.cpp | 73 ++------------------------- 3 files changed, 8 insertions(+), 112 deletions(-) diff --git a/cores/esp8266/Print.cpp b/cores/esp8266/Print.cpp index a1add0578..d93293ee8 100644 --- a/cores/esp8266/Print.cpp +++ b/cores/esp8266/Print.cpp @@ -268,47 +268,6 @@ size_t Print::printNumber(unsigned long n, uint8_t base) { } size_t Print::printFloat(double number, uint8_t digits) { - size_t n = 0; - - if(isnan(number)) - return print("nan"); - if(isinf(number)) - return print("inf"); - if(number > 4294967040.0) - return print("ovf"); // constant determined empirically - if(number < -4294967040.0) - return print("ovf"); // constant determined empirically - - // Handle negative numbers - if(number < 0.0) { - n += print('-'); - number = -number; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for(uint8_t i = 0; i < digits; ++i) - rounding /= 10.0; - - number += rounding; - - // Extract the integer part of the number and print it - unsigned long int_part = (unsigned long) number; - double remainder = number - (double) int_part; - n += print(int_part); - - // Print the decimal point, but only if there are digits beyond - if(digits > 0) { - n += print("."); - } - - // Extract digits from the remainder one at a time - while(digits-- > 0) { - remainder *= 10.0; - int toPrint = int(remainder); - n += print(toPrint); - remainder -= toPrint; - } - - return n; + char buf[40]; + return write(dtostrf(number, 0, digits, buf)); } diff --git a/cores/esp8266/Print.h b/cores/esp8266/Print.h index e620f14ad..e43883b39 100644 --- a/cores/esp8266/Print.h +++ b/cores/esp8266/Print.h @@ -26,6 +26,8 @@ #include "WString.h" #include "Printable.h" +#include "stdlib_noniso.h" + #define DEC 10 #define HEX 16 #define OCT 8 diff --git a/cores/esp8266/core_esp8266_noniso.cpp b/cores/esp8266/core_esp8266_noniso.cpp index b39edbb28..2d1fb7160 100644 --- a/cores/esp8266/core_esp8266_noniso.cpp +++ b/cores/esp8266/core_esp8266_noniso.cpp @@ -22,6 +22,7 @@ */ +#include #include #include #include @@ -40,75 +41,9 @@ char* ultoa(unsigned long value, char* result, int base) { } char * dtostrf(double number, signed char width, unsigned char prec, char *s) { - bool negative = false; - - if (isnan(number)) { - strcpy(s, "nan"); - return s; - } - if (isinf(number)) { - strcpy(s, "inf"); - return s; - } - - char* out = s; - - int fillme = width; // how many cells to fill for the integer part - if (prec > 0) { - fillme -= (prec+1); - } - - // Handle negative numbers - if (number < 0.0) { - negative = true; - fillme--; - number = -number; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - // I optimized out most of the divisions - double rounding = 2.0; - for (uint8_t i = 0; i < prec; ++i) - rounding *= 10.0; - rounding = 1.0 / rounding; - - number += rounding; - - // Figure out how big our number really is - double tenpow = 1.0; - int digitcount = 1; - while (number >= 10.0 * tenpow) { - tenpow *= 10.0; - digitcount++; - } - - number /= tenpow; - fillme -= digitcount; - - // Pad unused cells with spaces - while (fillme-- > 0) { - *out++ = ' '; - } - - // Handle negative sign - if (negative) *out++ = '-'; - - // Print the digits, and if necessary, the decimal point - digitcount += prec; - int8_t digit = 0; - while (digitcount-- > 0) { - digit = (int8_t)number; - if (digit > 9) digit = 9; // insurance - *out++ = (char)('0' | digit); - if ((digitcount == prec) && (prec > 0)) { - *out++ = '.'; - } - number -= digit; - number *= 10.0; - } - - // make sure the string is terminated - *out = 0; + char fmt[32]; + sprintf(fmt, "%%%d.%df", width, prec); + sprintf(s, fmt, number); return s; }