diff --git a/.gitignore b/.gitignore deleted file mode 100644 index f3bcf88..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ - -.pc diff --git a/.travis.yml b/.travis.yml index e76d4e8..277ce25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: go go: - - 1.8.x - 1.9.x + - 1.10.x script: go test diff --git a/bench_test.go b/bench_test.go index 97f8632..9e44ca9 100644 --- a/bench_test.go +++ b/bench_test.go @@ -61,7 +61,7 @@ if _, _, err := nums[i].SetString(buf.String()); err != nil { b.Fatal(err) } - nums[i].SetExponent(int32(s - numDigits)) + nums[i].Exponent = int32(s - numDigits) } b.Run( fmt.Sprintf("P%d/S%d/D%d", p, s, d), diff --git a/context.go b/context.go index 957aa3d..2fb3eae 100644 --- a/context.go +++ b/context.go @@ -182,12 +182,7 @@ if set, res, err := c.setIfNaN(d, x); set { return res, err } - if x.IsZero() { - d.Set(x) - d.Negative = false - } else { - d.Neg(x) - } + d.Neg(x) return c.Round(d, d) } @@ -501,13 +496,13 @@ // is odd or even. approx := new(Decimal) if e%2 == 0 { - approx.SetCoefficient(819).SetExponent(-3) + approx.SetFinite(819, -3) ed.Mul(approx, approx, f) ed.Add(approx, approx, New(259, -3)) } else { f.Exponent-- e++ - approx.SetCoefficient(259).SetExponent(-2) + approx.SetFinite(259, -2) ed.Mul(approx, approx, f) ed.Add(approx, approx, New(819, -4)) } @@ -728,7 +723,7 @@ // tmp1 = z - 1 ed.Sub(tmp1, z, decimalOne) // tmp3 = 0.1 - tmp3.SetCoefficient(1).SetExponent(-1) + tmp3.SetFinite(1, -1) usePowerSeries := false @@ -742,7 +737,7 @@ // We multiplied the input by 10^-expDelta, we will need to add // ln(10^expDelta) = expDelta * ln(10) // to the result. - resAdjust.SetCoefficient(int64(expDelta)) + resAdjust.setCoefficient(int64(expDelta)) ed.Mul(resAdjust, resAdjust, decimalLn10.get(p)) // tmp1 = z - 1 @@ -790,7 +785,7 @@ ed.Mul(tmp3, tmp3, tmp2) // tmp4 = 2n+1 - tmp4.SetCoefficient(int64(2*n + 1)).SetExponent(0) + tmp4.SetFinite(int64(2*n+1), 0) ed.Quo(tmp4, tmp3, tmp4) @@ -919,15 +914,14 @@ if x.Sign() < 0 { res = res.negateOverflowFlags() res |= Clamped - d.SetCoefficient(0) - d.Exponent = c.etiny() + d.SetFinite(0, c.etiny()) } else { d.Set(decimalInfinity) } return c.goError(res) } // if abs(x) <= setexp(.9, -currentprecision); then result 1 - tmp2.SetCoefficient(9).SetExponent(int32(-cp) - 1) + tmp2.SetFinite(9, int32(-cp)-1) if tmp1.Cmp(tmp2) <= 0 { d.Set(decimalOne) return c.goError(res) @@ -967,7 +961,7 @@ sum := New(1, 0) tmp2.Exponent = 0 for i := n - 1; i > 0; i-- { - tmp2.SetCoefficient(i) + tmp2.setCoefficient(i) // tmp1 = r / i ed.Quo(tmp1, r, tmp2) // sum = sum * r / i diff --git a/decimal.go b/decimal.go index 49fac15..03fd53c 100644 --- a/decimal.go +++ b/decimal.go @@ -89,10 +89,15 @@ // NewWithBigInt creates a new decimal with the given coefficient and exponent. func NewWithBigInt(coeff *big.Int, exponent int32) *Decimal { - return &Decimal{ - Coeff: *coeff, + d := &Decimal{ Exponent: exponent, } + d.Coeff.Set(coeff) + if d.Coeff.Sign() < 0 { + d.Negative = true + d.Coeff.Abs(&d.Coeff) + } + return d } func consumePrefix(s, prefix string) (string, bool) { @@ -226,25 +231,24 @@ // SetInt64 sets d to x and returns d. func (d *Decimal) SetInt64(x int64) *Decimal { - d.SetCoefficient(x) - d.Exponent = 0 + return d.SetFinite(x, 0) +} + +// SetFinite sets d to x with exponent e and returns d. +func (d *Decimal) SetFinite(x int64, e int32) *Decimal { + d.setCoefficient(x) + d.Exponent = e return d } -// SetCoefficient sets d's coefficient and negative value to x, its Form to -// Finite, and returns d. The exponent is not changed. -func (d *Decimal) SetCoefficient(x int64) *Decimal { +// setCoefficient sets d's coefficient and negative value to x and its Form +// to Finite The exponent is not changed. Since the exponent is not changed +// (and this is thus easy to misuse), this is unexported for internal use only. +func (d *Decimal) setCoefficient(x int64) { d.Negative = x < 0 d.Coeff.SetInt64(x) d.Coeff.Abs(&d.Coeff) d.Form = Finite - return d -} - -// SetExponent sets d's Exponent value to x and returns d. -func (d *Decimal) SetExponent(x int32) *Decimal { - d.Exponent = x - return d } // SetFloat64 sets d's Coefficient and Exponent to x and returns d. d will @@ -684,7 +688,11 @@ // Neg sets d to -x and returns d. func (d *Decimal) Neg(x *Decimal) *Decimal { d.Set(x) - d.Negative = !d.Negative + if d.IsZero() { + d.Negative = false + } else { + d.Negative = !d.Negative + } return d } @@ -707,8 +715,7 @@ switch x.Sign() { case 0: nd = int(d.NumDigits()) - d.SetCoefficient(0) - d.Exponent = 0 + d.SetInt64(0) return d, nd - 1 case -1: neg = true diff --git a/decimal_test.go b/decimal_test.go index 0287a08..1bc2b63 100644 --- a/decimal_test.go +++ b/decimal_test.go @@ -51,6 +51,35 @@ t.Fatalf("%s: %+v", s, err) } return d +} + +func TestNewWithBigInt(t *testing.T) { + tests := []string{ + "0", + "1", + "-1", + } + for _, tc := range tests { + t.Run(tc, func(t *testing.T) { + expect, _, err := new(Decimal).SetString(tc) + if err != nil { + t.Fatal(err) + } + b, ok := new(big.Int).SetString(tc, 10) + if !ok { + t.Fatal("bad bigint") + } + d := NewWithBigInt(b, 0) + if d.Coeff.Sign() < 0 { + t.Fatal("unexpected negative coeff") + } + // Verify that changing b doesn't change d. + b.Set(big.NewInt(1234)) + if d.CmpTotal(expect) != 0 { + t.Fatalf("expected %s, got %s", expect, d) + } + }) + } } func TestUpscale(t *testing.T) { @@ -690,6 +719,30 @@ z := d.IsZero() if z != tc.zero { t.Fatalf("got %v, expected %v", z, tc.zero) + } + }) + } +} + +func TestNeg(t *testing.T) { + tests := map[string]string{ + "0": "0", + "-0": "0", + "-0.000": "0.000", + "-00.000100": "0.000100", + } + + for tc, expect := range tests { + t.Run(tc, func(t *testing.T) { + d, _, err := NewFromString(tc) + if err != nil { + t.Fatal(err) + } + var z Decimal + z.Neg(d) + s := z.String() + if s != expect { + t.Fatalf("expected %s, got %s", expect, s) } }) } diff --git a/format.go b/format.go index 9d59883..3aea01f 100644 --- a/format.go +++ b/format.go @@ -23,7 +23,8 @@ // If format is a different character, Text returns a "%" followed by the // unrecognized.Format character. The 'f' format has the possibility of // displaying precision that is not present in the Decimal when it appends -// zeros. All other formats always show the exact precision of the Decimal. +// zeros (the 'g' format avoids the use of 'f' in this case). All other +// formats always show the exact precision of the Decimal. func (d *Decimal) Text(format byte) string { cap := 10 // TODO(gri) determine a good/better value here return string(d.Append(make([]byte, 0, cap), format)) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b5f8f21 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/cockroachdb/apd/v2 + +require github.com/pkg/errors v0.8.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..3dfe462 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=