Skip to content

Commit 1f73d13

Browse files
committed
ATLEDGE-619: fix dtostrf
Use a different method for float->string conversion, and fix the width calculation so that extra spaces are only printed if the width parameter exceeds the output string length (ie. a mininum width, as specified by dtostrf reference from avr-libc).
1 parent 2cd33f4 commit 1f73d13

File tree

2 files changed

+62
-64
lines changed

2 files changed

+62
-64
lines changed

cores/arduino/WString.cpp

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -813,26 +813,3 @@ float String::toFloat(void) const
813813
if (buffer) return float(atof(buffer));
814814
return 0;
815815
}
816-
817-
/*********************************************/
818-
/* utilities functions */
819-
/*********************************************/
820-
821-
int String::digitsBe4Decimal(double number)
822-
{
823-
int cnt = 1; // Always has one digit
824-
825-
// Count -ve sign as one digit
826-
if(number < 0.0) {
827-
cnt++;
828-
number = -number;
829-
}
830-
831-
// Count the number of digits beyond the 1st, basically, the exponent.
832-
while(number >= 10.0) {
833-
number /= 10;
834-
cnt++;
835-
}
836-
return cnt;
837-
}
838-

cores/arduino/stdlib_noniso.cpp

Lines changed: 62 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,31 @@ void shiftOutDigit(double *number, int count, char *s)
162162
*number = tmp;
163163
}
164164

165-
char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
165+
int digitsBe4Decimal(double number)
166+
{
167+
int cnt = 1; // Always has one digit
168+
169+
// Count -ve sign as one digit
170+
if(number < 0.0) {
171+
cnt++;
172+
number = -number;
173+
}
174+
175+
// Count the number of digits beyond the 1st, basically, the exponent.
176+
while(number >= 10.0) {
177+
number /= 10;
178+
cnt++;
179+
}
180+
return cnt;
181+
}
182+
183+
char *dtostrf(double number, signed char width, unsigned char prec, char *s)
184+
{
185+
char *out;
186+
unsigned long long integer;
187+
double fraction, rounding;
188+
int digit, before, i;
189+
int delta;
166190

167191
if (isnan(number)) {
168192
strcpy(s, "nan");
@@ -173,62 +197,59 @@ char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
173197
return s;
174198
}
175199

176-
char *out = s;
177-
int expCnt = 0, digit, totalWidth;
178-
double tmp, rounding;
200+
out = s;
201+
before = digitsBe4Decimal(number);
179202

180-
// Check for left adjustment (spaces)
181-
while(width < 0) {
182-
*out++ = ' ';
183-
width++;
203+
// check if padding is required
204+
if (width < 0) {
205+
delta = (-width) - (before + prec + 1);
206+
for (i = 0; i < delta; ++i) *out++ = ' ';
207+
width = 0;
184208
}
185-
totalWidth = (int)width;
186209

187210
// Handle negative numbers
188211
if (number < 0.0) {
189-
*out++ = '-';
212+
*out = '-';
190213
number = -number;
191-
if(totalWidth > 0) totalWidth--;
192214
}
193215

194-
// Rounding up to the precision
195-
tmp = number;
196-
rounding = 0.5;
197-
for(int i=0; i < prec; i++)
198-
rounding /= 10.0;
199-
tmp += rounding;
216+
// seperate integral and fractional parts
217+
integer = (unsigned long long) number;
218+
fraction = (double) (number - integer);
200219

201-
// Shifting the number to the right
202-
while( tmp >= 10.0 ) {
203-
tmp /= 10.0;
204-
expCnt++;
220+
// generate chars for each digit of the integral part
221+
i = before;
222+
while (integer > 10) {
223+
digit = integer % 10;
224+
out[(i--) - 1] = '0' + digit;
225+
integer /= 10;
205226
}
206227

207-
// 1st, print the single digit left after shifting
208-
digit = (int)tmp;
209-
*out++ = '0' + digit;
210-
tmp -= (double)digit;
211-
if(totalWidth > 0) totalWidth--;
228+
out[i - 1] = '0' + integer;
229+
out += before;
230+
if (!prec) goto end;
212231

213-
// Then the integer portion
214-
shiftOutDigit(&tmp, expCnt, out);
215-
out += expCnt;
216-
if(totalWidth > 0) totalWidth -= expCnt;
232+
// rounding up to the precision
233+
rounding = 0.5;
234+
for (i = 0; i < prec; ++i)
235+
rounding /= 10.0;
236+
fraction += rounding;
217237

218-
// Then the decimal portion
219-
if( prec ) {
220-
*out++ = '.';
221-
shiftOutDigit(&tmp, prec, out);
222-
if(totalWidth > 0) totalWidth -= (prec + 1);
223-
out += prec;
238+
// generate chars for each digit of the fractional part
239+
*out++ = '.';
240+
for (i = 0; i < prec; ++i) {
241+
fraction *= 10.0;
242+
digit = ((int) fraction) % 10;
243+
*out++ = '0' + digit;
224244
}
225245

226-
// Right adjustment
227-
while(totalWidth > 0) {
228-
*out++ = ' ';
229-
totalWidth--;
246+
end:
247+
// check if padding is required
248+
if (width > 0) {
249+
delta = width - (before + prec + 1);
250+
for (i = 0; i < delta; ++i) *out++ = ' ';
230251
}
231252

232-
*out = 0; // End of string
253+
*out = 0;
233254
return s;
234255
}

0 commit comments

Comments
 (0)