]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: remove Float.Round (not needed anymore), fix a bug in SetInt64
authorRobert Griesemer <gri@golang.org>
Sat, 14 Feb 2015 00:30:21 +0000 (16:30 -0800)
committerRobert Griesemer <gri@golang.org>
Sat, 14 Feb 2015 00:43:07 +0000 (00:43 +0000)
TBR adonovan

Change-Id: I30020f39be9183b37275e10a4fd1e1a3b4c48c89
Reviewed-on: https://go-review.googlesource.com/4880
Reviewed-by: Robert Griesemer <gri@golang.org>
src/math/big/float.go
src/math/big/float_test.go

index 971a9e5c56fb804b9b6105e3a336f6e42d3dfcbc..dd6700137befbf0f812532916b33c25cedf7b918 100644 (file)
@@ -147,6 +147,7 @@ func (mode RoundingMode) String() string {
 // cannot be represented in prec bits without loss of precision.
 func (z *Float) SetPrec(prec uint) *Float {
        old := z.prec
+       z.acc = Exact
        z.prec = prec
        if prec < old {
                z.round(0)
@@ -154,9 +155,10 @@ func (z *Float) SetPrec(prec uint) *Float {
        return z
 }
 
-// SetMode sets z's rounding mode to mode and returns z.
+// SetMode sets z's rounding mode to mode and returns an exact z.
 // z remains unchanged otherwise.
 func (z *Float) SetMode(mode RoundingMode) *Float {
+       z.acc = Exact
        z.mode = mode
        return z
 }
@@ -436,16 +438,6 @@ func (z *Float) round(sbit uint) {
        return
 }
 
-// Round sets z to the value of x rounded according to mode to prec bits and returns z.
-// TODO(gri) rethink this signature.
-func (z *Float) Round(x *Float, prec uint, mode RoundingMode) *Float {
-       z.Copy(x)
-       z.prec = prec
-       z.mode = mode
-       z.round(0)
-       return z
-}
-
 // nlz returns the number of leading zero bits in x.
 func nlz(x Word) uint {
        return _W - uint(bitLen(x))
@@ -465,15 +457,12 @@ func nlz64(x uint64) uint {
        panic("unreachable")
 }
 
-// SetUint64 sets z to the (possibly rounded) value of x and returns z.
-// If z's precision is 0, it is changed to 64 (and rounding will have
-// no effect).
-func (z *Float) SetUint64(x uint64) *Float {
+func (z *Float) setBits64(neg bool, x uint64) *Float {
        if z.prec == 0 {
                z.prec = 64
        }
        z.acc = Exact
-       z.neg = false
+       z.neg = neg
        if x == 0 {
                z.mant = z.mant[:0]
                z.exp = 0
@@ -489,6 +478,13 @@ func (z *Float) SetUint64(x uint64) *Float {
        return z
 }
 
+// SetUint64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 64 (and rounding will have
+// no effect).
+func (z *Float) SetUint64(x uint64) *Float {
+       return z.setBits64(false, x)
+}
+
 // SetInt64 sets z to the (possibly rounded) value of x and returns z.
 // If z's precision is 0, it is changed to 64 (and rounding will have
 // no effect).
@@ -497,9 +493,9 @@ func (z *Float) SetInt64(x int64) *Float {
        if u < 0 {
                u = -u
        }
-       z.SetUint64(uint64(u))
-       z.neg = x < 0
-       return z
+       // We cannot simply call z.SetUint64(uint64(u)) and change
+       // the sign afterwards because the sign affects rounding.
+       return z.setBits64(x < 0, uint64(u))
 }
 
 // SetFloat64 sets z to the (possibly rounded) value of x and returns z.
@@ -599,6 +595,7 @@ func (z *Float) SetRat(x *Rat) *Float {
 // mode; and z's accuracy reports the result error relative to the
 // exact (not rounded) result.
 func (z *Float) Set(x *Float) *Float {
+       // TODO(gri) what about z.acc? should it be always Exact?
        if z != x {
                if z.prec == 0 {
                        z.prec = x.prec
@@ -617,6 +614,7 @@ func (z *Float) Set(x *Float) *Float {
 // Copy sets z to x, with the same precision and rounding mode as x,
 // and returns z.
 func (z *Float) Copy(x *Float) *Float {
+       // TODO(gri) what about z.acc? should it be always Exact?
        if z != x {
                z.acc = Exact
                z.neg = x.neg
@@ -761,7 +759,9 @@ func (x *Float) Float64() (float64, Accuracy) {
                return 0, Exact
        }
        // x != 0
-       r := new(Float).Round(x, 53, ToNearestEven)
+       var r Float
+       r.prec = 53
+       r.Set(x)
        var s uint64
        if r.neg {
                s = 1 << 63
index db4b52b4e09624c79a18aaf30f0ccfb5bb8f8acd..8ed7f0a4adc6ed4e35d0231ac19b649e0c3fe2f5 100644 (file)
@@ -263,18 +263,46 @@ func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) {
        }
 
        // round
-       f := new(Float).SetInt64(x)
-       f.Round(f, prec, mode)
+       f := new(Float).SetMode(mode).SetInt64(x).SetPrec(prec)
 
        // check result
        r1 := f.int64()
        p1 := f.Prec()
        a1 := f.Acc()
        if r1 != r || p1 != prec || a1 != a {
-               t.Errorf("Round(%s, %d, %s): got %s (%d bits, %s); want %s (%d bits, %s)",
+               t.Errorf("round %s (%d bits, %s) incorrect: got %s (%d bits, %s); want %s (%d bits, %s)",
                        toBinary(x), prec, mode,
                        toBinary(r1), p1, a1,
                        toBinary(r), prec, a)
+               return
+       }
+
+       // g and f should be the same
+       // (rounding by SetPrec after SetInt64 using default precision
+       // should be the same as rounding by SetInt64 after setting the
+       // precision)
+       g := new(Float).SetMode(mode).SetPrec(prec).SetInt64(x)
+       if !feq(g, f) {
+               t.Errorf("round %s (%d bits, %s) not symmetric: got %s and %s; want %s",
+                       toBinary(x), prec, mode,
+                       toBinary(g.int64()),
+                       toBinary(r1),
+                       toBinary(r),
+               )
+               return
+       }
+
+       // h and f should be the same
+       // (repeated rounding should be idempotent)
+       h := new(Float).SetMode(mode).SetPrec(prec).Set(f)
+       if !feq(h, f) {
+               t.Errorf("round %s (%d bits, %s) not idempotent: got %s and %s; want %s",
+                       toBinary(x), prec, mode,
+                       toBinary(h.int64()),
+                       toBinary(r1),
+                       toBinary(r),
+               )
+               return
        }
 }
 
@@ -383,8 +411,7 @@ func TestFloatRound24(t *testing.T) {
        const x0 = 1<<26 - 0x10 // 11...110000 (26 bits)
        for d := 0; d <= 0x10; d++ {
                x := float64(x0 + d)
-               f := new(Float).SetFloat64(x)
-               f.Round(f, 24, ToNearestEven)
+               f := new(Float).SetPrec(24).SetFloat64(x)
                got, _ := f.Float64()
                want := float64(float32(x))
                if got != want {