From 2adc96bca4c765c7743c2b68c74418ba0bb6dd7f Mon Sep 17 00:00:00 2001 From: Sasha Mitchell Date: Sat, 10 Oct 2026 01:38:24 +0700 Subject: [PATCH] fix: keep the decimal point when rounding gains a digit Formatting 9.996 with %.2f printed 1.000. A carry from 999 to 1000 was counted as a discarded place, so the point moved left by one. Fixes #178 Fixes #198 --- format.go | 15 +++++++-------- format_test.go | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/format.go b/format.go index 8a34100..4ce9513 100644 --- a/format.go +++ b/format.go @@ -209,8 +209,11 @@ func (f *formatter) format(x *Big, format format, e byte) { b = formatUnscaled(&x.unscaled) } orig := len(b) - b = roundString(b, x.Context.RoundingMode, !neg, f.prec) - exp = int(x.exp) + orig - len(b) + // A carry from 999 to 1000 adds a digit. That digit is a new leading + // place, so the scale stays tied to the requested precision. + req := f.prec + b = roundString(b, x.Context.RoundingMode, !neg, req) + exp = int(x.exp) + orig - req } else if f.prec < 0 { f.prec = -f.prec exp = -f.prec @@ -283,12 +286,8 @@ func (f *formatter) formatPlain(b []byte, exp int) { default: f.WriteString(zeroRadix) io.CopyN(f, zeroReader{}, -int64(radix)) - - end := len(b) - if f.prec < end { - end = f.prec - } - f.Write(b[:end]) + // Keep a carry digit. Dropping it shifts the value by a factor of ten. + f.Write(b) } } diff --git a/format_test.go b/format_test.go index 3c643a1..19a432d 100644 --- a/format_test.go +++ b/format_test.go @@ -76,6 +76,22 @@ func TestDecimal_Format(t *testing.T) { {"%.10f", "0.1234567891", "0.1234567891"}, {"%.10f", "0.01", "0.0100000000"}, {"%.10f", "0.0000000000000000000000000000000000000000000000000000000000001", "0.0000000000"}, + // Rounding that gains a digit must not move the point one place left. + {"%.2f", "9.996208266660", "10.00"}, + {"%.6f", "0.099999999999999999999999999999998", "0.100000"}, + {"%.1f", "9.96", "10.0"}, + {"%.0f", "9.96", "10"}, + {"%.1f", "-9.96", "-10.0"}, + {"%.0f", "999.5", "1000"}, + {"%.3f", "0.09996", "0.100"}, + {"%.3f", "0.9996", "1.000"}, + {"%.1f", "99.96", "100.0"}, + {"%.3f", "0.009996", "0.010"}, + {"%.2e", "9.96", "1.00e+1"}, + {"%.1f", "9.94", "9.9"}, + {"%.1f", "1.25", "1.2"}, + {"%.0f", "1.5", "2"}, + {"%.0f", "2.5", "2"}, } { z, _ := new(Big).SetString(s.input) got := fmt.Sprintf(s.format, z)