From: Robert Griesemer Date: Wed, 27 May 2015 21:43:30 +0000 (-0700) Subject: math/big: fix latent decimal conversion bug X-Git-Tag: go1.5beta1~454 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0c02b33acda207964adde58b610b6f2c82ffde1d;p=gostls13.git math/big: fix latent decimal conversion bug A decimal represented 0.0 with a 0-length mantissa and undefined exponent, but the formatting code assumes a valid zero exponent if the float value is 0.0. The code worked because we allocate a new decimal value each time and because there's no rounding that lead to 0.0. Change-Id: Ifd771d7709de83b87fdbf141786286b4c3e13d4f Reviewed-on: https://go-review.googlesource.com/10448 Reviewed-by: Alan Donovan --- diff --git a/src/math/big/decimal.go b/src/math/big/decimal.go index 3d024dce68..2595e5f8c1 100644 --- a/src/math/big/decimal.go +++ b/src/math/big/decimal.go @@ -19,12 +19,14 @@ package big -// A decimal represents a floating-point number in decimal representation. -// The value of a decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1, -// with the most-significant mantissa digit at index 0. +// A decimal represents an unsigned floating-point number in decimal representation. +// The value of a non-zero decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1, +// with the most-significant mantissa digit at index 0. For the zero decimal, the +// mantissa length and exponent are 0. +// The zero value for decimal represents a ready-to-use 0.0. type decimal struct { mant []byte // mantissa ASCII digits, big-endian - exp int // exponent, valid if len(mant) > 0 + exp int // exponent } // Maximum shift amount that can be done in one pass without overflow. @@ -46,6 +48,7 @@ func (x *decimal) init(m nat, shift int) { // special case 0 if len(m) == 0 { x.mant = x.mant[:0] + x.exp = 0 return } @@ -255,4 +258,7 @@ func trim(x *decimal) { i-- } x.mant = x.mant[:i] + if i == 0 { + x.exp = 0 + } } diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go index db300314f1..9fc2b89fb9 100644 --- a/src/math/big/floatconv_test.go +++ b/src/math/big/floatconv_test.go @@ -125,12 +125,16 @@ func TestFloat64Format(t *testing.T) { {1, 'f', 0, "1"}, {-1, 'f', 0, "-1"}, + {0.001, 'e', 0, "1e-03"}, + {0.459, 'e', 0, "5e-01"}, {1.459, 'e', 0, "1e+00"}, {2.459, 'e', 1, "2.5e+00"}, {3.459, 'e', 2, "3.46e+00"}, {4.459, 'e', 3, "4.459e+00"}, {5.459, 'e', 4, "5.4590e+00"}, + {0.001, 'f', 0, "0"}, + {0.459, 'f', 0, "0"}, {1.459, 'f', 0, "1"}, {2.459, 'f', 1, "2.5"}, {3.459, 'f', 2, "3.46"}, diff --git a/src/math/big/ftoa.go b/src/math/big/ftoa.go index 0f943e1ff2..4c3e743d6c 100644 --- a/src/math/big/ftoa.go +++ b/src/math/big/ftoa.go @@ -58,7 +58,7 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte { } // Inf - if x.IsInf() { + if x.form == inf { if !x.neg { buf = append(buf, '+') } @@ -79,12 +79,10 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte { // 3) read digits out and format // 1) convert Float to multiprecision decimal - var mant nat + var d decimal // == 0.0 if x.form == finite { - mant = x.mant + d.init(x.mant, int(x.exp)-x.mant.bitLen()) } - var d decimal - d.init(mant, int(x.exp)-x.mant.bitLen()) // 2) round to desired precision shortest := false