diff --git a/cores/esp8266/core_esp8266_noniso.c b/cores/esp8266/core_esp8266_noniso.c index 0b53583fd..d5b9d82f2 100644 --- a/cores/esp8266/core_esp8266_noniso.c +++ b/cores/esp8266/core_esp8266_noniso.c @@ -148,7 +148,8 @@ 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; @@ -158,14 +159,17 @@ char * dtostrf(double number, signed char width, unsigned char prec, char *s) { return s; } - if (number > 4294967040.0 || number < -4294967040.0) { - strcpy(s, "ovf"); - 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) { - *out++ = '-'; + negative = true; + fillme--; number = -number; } @@ -173,39 +177,47 @@ char * dtostrf(double number, signed char width, unsigned char prec, char *s) { // 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; + rounding *= 10.0; + rounding = 1.0 / rounding; 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; - out += sprintf(out, "%d", int_part); - - // Print the decimal point, but only if there are digits beyond - if (prec > 0) { - *out++ = '.'; + + // Figure out how big our number really is + double tenpow = 1.0; + int digitcount = 1; + while (number >= 10.0 * tenpow) { + tenpow *= 10.0; + digitcount++; } - // make sure the string is terminated before mesuring it length - *out = 0; - // Reduce minimum width accordingly - width -= strlen(s); - - // Print the digits after the decimal point + + 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 (prec-- > 0) { - remainder *= 10.0; - digit = (int8_t)remainder; + while (digitcount-- > 0) { + digit = (int8_t)number; if (digit > 9) digit = 9; // insurance *out++ = (char)('0' | digit); - width--; - remainder -= digit; + if ((digitcount == prec) && (prec > 0)) { + *out++ = '.'; + } + number -= digit; + number *= 10.0; } - // add '0' to fill minimum width requirement - while (width-- > 0) *out++ = ' '; + // make sure the string is terminated *out = 0; return s; } +