From ab4d78ac89a4ba502890077cfee4a5444801e865 Mon Sep 17 00:00:00 2001 From: Denis Bernard Date: Mon, 1 Jun 2020 17:34:22 +0200 Subject: [PATCH] Decimal: SetInt: default precision uses whole input magnitude When z.prec is zero, compute precision based on all decimal digits in source big.Int, including trailing zeros (i.e. the precision should match the magnitude of the input, regardless of its actual value). Before the change, trailing zero digits were ignored. --- decimal.go | 16 ++++++++++------ decimal_test.go | 4 ++-- decimal_toa.go | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/decimal.go b/decimal.go index a553aa8..efdf414 100644 --- a/decimal.go +++ b/decimal.go @@ -1147,12 +1147,16 @@ func (z *Decimal) SetInt(x *big.Int) *Decimal { // TODO(db47h) truncating x could be more efficient if z.prec > 0 // but small compared to the size of x. z.mant = z.mant.make(int((prec + _DW - 1) / _DW)).setNat(x.Bits()) - exp := dnorm(z.mant) if z.prec == 0 { - // adjust precision - z.prec = uint32(max(len(z.mant)*_DW-int(z.mant.trailingZeroDigits()), DefaultDecimalPrec)) + // adjust precision. z.mant is not notmalized yet. use nlz() and accept + // trailing zeros as part of the required precision + digits := int64(len(z.mant))*_DW - int64(nlz10(z.mant[len(z.mant)-1])) + if digits > MaxPrec { + digits = MaxPrec + } + z.prec = umax32(uint32(digits), DefaultDecimalPrec) } - z.setExpAndRound(int64(len(z.mant))*_DW-exp, 0) + z.setExpAndRound(int64(len(z.mant))*_DW-dnorm(z.mant), 0) return z } @@ -1584,9 +1588,9 @@ func dnorm(m dec) int64 { if debugDecimal && (len(m) == 0 || m[len(m)-1] == 0) { panic("msw of mantissa is 0") } - s := _DW - decDigits(uint(m[len(m)-1])) - // partial shift + s := nlz10(m[len(m)-1]) if s > 0 { + // partial shift c := shl10VU(m, m, s) if debugDecimal && c != 0 { panic("nlz or shlVU incorrect") diff --git a/decimal_test.go b/decimal_test.go index 37dd3d4..ef3fecb 100644 --- a/decimal_test.go +++ b/decimal_test.go @@ -721,7 +721,7 @@ func TestDecimalSetInt(t *testing.T) { f.SetInt(&x) // check precision - n := len(strings.TrimRight(want, "0")) + n := len(want) if n < DefaultDecimalPrec { n = DefaultDecimalPrec } @@ -747,7 +747,7 @@ func TestDecimalSetRat(t *testing.T) { {"-1", DefaultDecimalPrec}, {"1234567890", DefaultDecimalPrec}, {"123456789012345678901234567890", DefaultDecimalPrec}, - {"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", 89}, + {"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", 90}, {"1.2", DefaultDecimalPrec}, {"3.14159265", DefaultDecimalPrec}, // TODO(db47h) expand diff --git a/decimal_toa.go b/decimal_toa.go index 975dcd8..4713c66 100644 --- a/decimal_toa.go +++ b/decimal_toa.go @@ -346,7 +346,7 @@ func (x *Decimal) fmtP(buf []byte) []byte { mant, exp := x.toa(10) buf = append(buf, bytes.TrimRight(mant, "0")...) buf = append(buf, 'e') - if x.exp >= 0 { + if exp >= 0 { buf = append(buf, '+') } return strconv.AppendInt(buf, int64(exp), 10)