From cb1bfecb13191b14badc9d680ede2654e7f9aae9 Mon Sep 17 00:00:00 2001 From: Denis Bernard Date: Mon, 4 May 2020 19:00:48 +0200 Subject: [PATCH] dec: refactor digits -> ntz --- dec.go | 11 +++++++++-- arith_dec.go => dec_arith.go | 13 +++++++------ dec_test.go | 13 ++++++------- decimal.go | 4 ++-- decimal_test.go | 4 ++-- 5 files changed, 26 insertions(+), 19 deletions(-) rename arith_dec.go => dec_arith.go (95%) diff --git a/dec.go b/dec.go index 07f8362..ca6b7eb 100644 --- a/dec.go +++ b/dec.go @@ -45,11 +45,18 @@ func (z dec) norm() dec { return z[0:i] } -// TODO(db47h): change this to retun # of trailing zeroes. +// digits returns the number of digits of x. func (x dec) digits() uint { + if i := len(x) - 1; i >= 0 { + return uint(i*_W) + decDigits(uint(x[i])) + } + return 0 +} + +func (x dec) ntz() uint { for i, w := range x { if w != 0 { - return uint(len(x)-i)*_WD - decTrailingZeros(uint(w)) + return uint(i)*_WD + decTrailingZeros(uint(w)) } } return 0 diff --git a/arith_dec.go b/dec_arith.go similarity index 95% rename from arith_dec.go rename to dec_arith.go index 764f3d4..53087de 100644 --- a/arith_dec.go +++ b/dec_arith.go @@ -19,14 +19,15 @@ var maxDigits = [...]uint{ 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, } -// mag returns the magnitude of x such that 10**(mag-1) <= x < 10**mag. +// decDigits returns n such that of x such that 10**(n-1) <= x < 10**n. +// In other words, n the number of digits required to represent n. // Returns 0 for x == 0. -func mag(x uint) uint { - d := maxDigits[bits.Len(x)] - if x < pow10(d-1) { - d-- +func decDigits(x uint) (n uint) { + n = maxDigits[bits.Len(x)] + if x < pow10(n-1) { + n-- } - return d + return n } // shl10VU sets z to x*(10**s), s < _WD diff --git a/dec_test.go b/dec_test.go index 9b8321c..cf88abe 100644 --- a/dec_test.go +++ b/dec_test.go @@ -9,12 +9,12 @@ import ( "time" ) -func Test_dec_digits(t *testing.T) { +func TestDec_ntz(t *testing.T) { rand.Seed(time.Now().UnixNano()) for i := 0; i < 10000; i++ { again: w := uint(rand.Uint64()) % _BD - // ignore anything divisible by ten since mag(10) = 2 but dec{100000000...}.digits() = 1 + // TODO: WTF? ignore anything divisible by ten since decDigits(10) = 2 but dec{100000000...}.digits() = 1 if w%10 == 0 { goto again } @@ -22,9 +22,8 @@ func Test_dec_digits(t *testing.T) { h, l := bits.Mul(w, pow10(e)) h, l = bits.Div(h, l, _BD) d := dec{Word(l), Word(h)}.norm() - dnorm(d) - if d.digits() != mag(w) { - t.Fatalf("dec{%d}.digits() = %d, expected %d", d[0], d.digits(), mag(w)) + if d.ntz() != e { + t.Fatalf("dec{%v}.digits() = %d, expected %d", d, d.ntz(), e) } } } @@ -37,7 +36,7 @@ func Test_mag(t *testing.T) { for m := n; m != 0; m /= 10 { d++ } - if dd := mag(n); dd != d { + if dd := decDigits(n); dd != d { t.Fatalf("mag(%d) = %d, expected %d", n, dd, d) } } @@ -124,7 +123,7 @@ var ( func Benchmark_mag(b *testing.B) { rand.Seed(0xdeadbeefbadf00d) for i := 0; i < b.N; i++ { - benchU = mag(uint(rand.Uint64()) % _BD) + benchU = decDigits(uint(rand.Uint64()) % _BD) } } diff --git a/decimal.go b/decimal.go index 6e264bd..5fc6c9d 100644 --- a/decimal.go +++ b/decimal.go @@ -97,7 +97,7 @@ func (x *Decimal) MinPrec() uint { if x.form != finite { return 0 } - return x.mant.digits() + return uint(len(x.mant))*_WD - x.mant.ntz() } // Mode returns the rounding mode of x. @@ -446,7 +446,7 @@ func dnorm(m dec) int64 { if debugDecimal && (len(m) == 0 || m[len(m)-1] == 0) { panic("msw of mantissa is 0") } - s := _WD - mag(uint(m[len(m)-1])) + s := _WD - decDigits(uint(m[len(m)-1])) // partial shift if s > 0 { c := shl10VU(m, m, s) diff --git a/decimal_test.go b/decimal_test.go index a80ba30..361718a 100644 --- a/decimal_test.go +++ b/decimal_test.go @@ -48,8 +48,8 @@ func TestDnorm(t *testing.T) { dd := dec{}.set(d) s := dnorm(dd) // d should now have a single element with e shifted left - ew := w * pow10(_WD-mag(w)) - es := int64(uint(len(d)*_WD) - (mag(w) + e)) + ew := w * pow10(_WD-decDigits(w)) + es := int64(uint(len(d)*_WD) - (decDigits(w) + e)) if dd[len(dd)-1] != Word(ew) || s != es { t.Fatalf("%ve%v => dnorm(%v) = %v, %v --- Expected %d, %d", w, e, d, dd, s, w, es)