From ccb2eb9b7416fe6fd94d063cd96323b5c6f69705 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 27 Feb 2026 11:16:03 +0900 Subject: [PATCH] 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 --- src/fmt_fp.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/fmt_fp.c b/src/fmt_fp.c index ab69486e6..173cc3b58 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -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++ = '.';