fmt_fp.c: fix float formatting on 32-bit x87 FPU

The power-of-10 normalization loop can leave f >= 10.0 when x87
extended precision (80-bit) produces different rounding than 64-bit
SSE2. This caused garbled output (e.g. "0.0,6.04*2000001e+19"
instead of "1.0e+20") because negative digit values were added to
'0'. Add a correction step after the loop, and clamp extracted
digits to [0,9] for robustness.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-02-27 11:16:03 +09:00
parent 07a4b755fb
commit ccb2eb9b74
+9 -1
View File
@@ -222,6 +222,12 @@ mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, ch
f *= *neg_pow;
}
}
// correct for FP rounding errors in the power-of-10 loop
// (e.g. x87 extended precision can leave f >= 10.0)
if (f >= 10.0) {
f *= 0.1;
e++;
}
// If the user specified fixed format (fmt == 'f') and e makes the
// number too big to fit into the available buffer, then we'll
@@ -284,7 +290,9 @@ mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, ch
// Print the digits of the mantissa
for (int i = 0; i < num_digits; i++,dec--) {
int8_t d = (int8_t)((int)f)%10;
int8_t d = (int8_t)f;
if (d > 9) d = 9;
if (d < 0) d = 0;
*s++ = '0' + d;
if (dec == 0 && (prec > 0 || alt_form)) {
*s++ = '.';