2222
2323 */
2424
25- #include < stdio.h>
2625#include < stdlib.h>
2726#include < string.h>
2827#include < stdbool.h>
2928#include < stdint.h>
3029#include < math.h>
30+ #include < limits>
3131#include " stdlib_noniso.h"
3232
3333extern " C" {
@@ -41,9 +41,79 @@ char* ultoa(unsigned long value, char* result, int base) {
4141}
4242
4343char * dtostrf (double number, signed char width, unsigned char prec, char *s) {
44- char fmt[32 ];
45- sprintf (fmt, " %%%d.%df" , width, prec);
46- sprintf (s, fmt, number);
44+ bool negative = false ;
45+
46+ if (isnan (number)) {
47+ strcpy (s, " nan" );
48+ return s;
49+ }
50+ if (isinf (number)) {
51+ strcpy (s, " inf" );
52+ return s;
53+ }
54+
55+ char * out = s;
56+
57+ int fillme = width; // how many cells to fill for the integer part
58+ if (prec > 0 ) {
59+ fillme -= (prec+1 );
60+ }
61+
62+ // Handle negative numbers
63+ if (number < 0.0 ) {
64+ negative = true ;
65+ fillme--;
66+ number = -number;
67+ }
68+
69+ // Round correctly so that print(1.999, 2) prints as "2.00"
70+ // I optimized out most of the divisions
71+ double rounding = 2.0 ;
72+ for (uint8_t i = 0 ; i < prec; ++i)
73+ rounding *= 10.0 ;
74+ rounding = 1.0 / rounding;
75+
76+ number += rounding;
77+
78+ // Figure out how big our number really is
79+ double tenpow = 1.0 ;
80+ int digitcount = 1 ;
81+ double nextpow;
82+ while (number >= (nextpow = (10.0 * tenpow))) {
83+ tenpow = nextpow;
84+ digitcount++;
85+ }
86+
87+ // minimal compensation for possible lack of precision (#7087 addition)
88+ number *= 1 + std::numeric_limits<decltype (number)>::epsilon ();
89+
90+ number /= tenpow;
91+ fillme -= digitcount;
92+
93+ // Pad unused cells with spaces
94+ while (fillme-- > 0 ) {
95+ *out++ = ' ' ;
96+ }
97+
98+ // Handle negative sign
99+ if (negative) *out++ = ' -' ;
100+
101+ // Print the digits, and if necessary, the decimal point
102+ digitcount += prec;
103+ int8_t digit = 0 ;
104+ while (digitcount-- > 0 ) {
105+ digit = (int8_t )number;
106+ if (digit > 9 ) digit = 9 ; // insurance
107+ *out++ = (char )(' 0' | digit);
108+ if ((digitcount == prec) && (prec > 0 )) {
109+ *out++ = ' .' ;
110+ }
111+ number -= digit;
112+ number *= 10.0 ;
113+ }
114+
115+ // make sure the string is terminated
116+ *out = 0 ;
47117 return s;
48118}
49119
0 commit comments