Skip to content

Commit a54f513

Browse files
committed
Jira-575, Jira-506: Bug fixes to print float and double correctly, in a string or std output.
1 parent 2eb99d1 commit a54f513

File tree

4 files changed

+102
-18
lines changed

4 files changed

+102
-18
lines changed

cores/arduino/Print.cpp

+23-6
Original file line numberDiff line numberDiff line change
@@ -289,18 +289,29 @@ size_t Print::printLongLong(unsigned long long n, uint8_t base) {
289289
size_t Print::printFloat(double number, uint8_t digits)
290290
{
291291
size_t n = 0;
292+
int exponent = 0;
293+
double tmp;
292294

293295
if (isnan(number)) return print("nan");
294296
if (isinf(number)) return print("inf");
295-
if (number > 4294967040.0) return print ("ovf"); // constant determined empirically
296-
if (number <-4294967040.0) return print ("ovf"); // constant determined empirically
297297

298298
// Handle negative numbers
299-
if (number < 0.0)
300-
{
301-
n += print('-');
302-
number = -number;
299+
if (number < 0.0) {
300+
n += print('-');
301+
number = -number;
302+
}
303+
304+
// Chk if integer part has more than 8 digits.
305+
tmp = number;
306+
while (true) {
307+
tmp /= 10.0;
308+
exponent++;
309+
if (tmp < 10.0) break;
303310
}
311+
if (exponent > 8)
312+
number = tmp;
313+
else
314+
exponent = 0;
304315

305316
// Round correctly so that print(1.999, 2) prints as "2.00"
306317
double rounding = 0.5;
@@ -328,5 +339,11 @@ size_t Print::printFloat(double number, uint8_t digits)
328339
remainder -= toPrint;
329340
}
330341

342+
// Print the exponent portion
343+
if (exponent) {
344+
n += print("e+");
345+
n += print(exponent);
346+
}
347+
331348
return n;
332349
}

cores/arduino/WString.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,14 @@ String::String(float value, unsigned char decimalPlaces)
135135
{
136136
init();
137137
char buf[33];
138-
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
138+
*this = dtostrf(value, (33 - 1), decimalPlaces, buf);
139139
}
140140

141141
String::String(double value, unsigned char decimalPlaces)
142142
{
143143
init();
144144
char buf[33];
145-
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
145+
*this = dtostrf(value, (33 - 1), decimalPlaces, buf);
146146
}
147147

148148
String::~String()
@@ -363,14 +363,14 @@ unsigned char String::concat(unsigned long long num)
363363
unsigned char String::concat(float num)
364364
{
365365
char buf[20];
366-
char* string = dtostrf(num, 4, 2, buf);
366+
char* string = dtostrf(num, (20 - 1), 2, buf);
367367
return concat(string, strlen(string));
368368
}
369369

370370
unsigned char String::concat(double num)
371371
{
372372
char buf[20];
373-
char* string = dtostrf(num, 4, 2, buf);
373+
char* string = dtostrf(num, (20 - 1), 2, buf);
374374
return concat(string, strlen(string));
375375
}
376376

cores/arduino/stdlib_noniso.cpp

+73-6
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,76 @@ char* ultoa( unsigned long val, char *string, int radix )
147147
return string;
148148
}
149149

150-
char *dtostrf (double val, signed char width, unsigned char prec, char *sout) {
151-
char fmt[20];
152-
sprintf(fmt, "%%%d.%df", width, prec);
153-
sprintf(sout, fmt, val);
154-
return sout;
155-
}
150+
char * dtostrf(double number, unsigned char width, unsigned char prec, char *s) {
151+
152+
if (isnan(number)) {
153+
strcpy(s, "nan");
154+
return s;
155+
}
156+
if (isinf(number)) {
157+
strcpy(s, "inf");
158+
return s;
159+
}
160+
161+
char* out = s;
162+
int exponent = 0;
163+
unsigned char len, expLen;
164+
double tmp;
165+
166+
// Handle negative numbers
167+
if (number < 0.0) {
168+
*out++ = '-';
169+
number = -number;
170+
}
171+
172+
// The integer portion has to be <= 8 digits. Otherwise, the
173+
// string is in exponent format.
174+
tmp = number;
175+
for (;;) {
176+
tmp /= 10.0;
177+
exponent++;
178+
if (tmp < 10.0) break;
179+
}
180+
if (exponent > 8)
181+
number = tmp;
182+
else
183+
exponent = 0;
184+
185+
// Round correctly so that print(1.999, 2) prints as "2.00"
186+
double rounding = 0.5;
187+
for (uint8_t i = 0; i < prec; ++i)
188+
rounding /= 10.0;
189+
190+
number += rounding;
191+
192+
// Extract the integer part of the number and print it
193+
unsigned long int_part = (unsigned long)number;
194+
double remainder = number - (double)int_part;
195+
out += sprintf(out, "%ld", int_part);
196+
197+
// Don't go beyond the given width of the string
198+
len = (unsigned char)(out - s);
199+
expLen = (exponent == 0) ? 0 : 5; // 5 places for exponent expression
200+
if ((prec + len + expLen) > width)
201+
prec = width - len - expLen;
202+
203+
// Print the decimal point, but only if there are digits beyond
204+
if (prec > 0) {
205+
*out = '.';
206+
++out;
207+
prec--;
208+
// Copy character by character to 'out' string
209+
for (unsigned char decShift = prec; decShift > 0; decShift--) {
210+
remainder *= 10.0;
211+
sprintf(out, "%d", (int)remainder);
212+
out++;
213+
remainder -= (double)(int)remainder;
214+
}
215+
}
216+
217+
// Print the exponent if exists
218+
if (exponent)
219+
sprintf(out, "e+%.3d", exponent);
220+
221+
return s;
222+
}

cores/arduino/stdlib_noniso.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ char* utoa (unsigned int val, char *s, int radix);
3737

3838
char* ultoa (unsigned long val, char *s, int radix);
3939

40-
char* dtostrf (double val, signed char width, unsigned char prec, char *s);
40+
char* dtostrf (double val, unsigned char width, unsigned char prec, char *s);
4141

4242
#ifdef __cplusplus
4343
} // extern "C"
4444
#endif
4545

46-
#endif
46+
#endif

0 commit comments

Comments
 (0)