]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: fix Add, Sub when receiver aliases 2nd operand
authorAlberto Donizetti <alb.donizetti@gmail.com>
Thu, 25 May 2017 09:50:40 +0000 (11:50 +0200)
committerAlberto Donizetti <alb.donizetti@gmail.com>
Wed, 31 May 2017 10:28:05 +0000 (10:28 +0000)
Fixes #20490

Change-Id: I9cfa604f9ff94df779cb9b4cbbd706258fc473ac
Reviewed-on: https://go-review.googlesource.com/44150
Run-TryBot: Alberto Donizetti <alb.donizetti@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/math/big/float.go
src/math/big/float_test.go

index ac5464b1279eb5da5e9b8f906ad7d81cd936e5d7..7e11f1aff5815ad467ff012dd443eb9f2f2450d3 100644 (file)
@@ -1439,8 +1439,16 @@ func (z *Float) Add(x, y *Float) *Float {
 
        if x.form == finite && y.form == finite {
                // x + y (common case)
+
+               // Below we set z.neg = x.neg, and when z aliases y this will
+               // change the y operand's sign. This is fine, because if an
+               // operand aliases the receiver it'll be overwritten, but we still
+               // want the original x.neg and y.neg values when we evaluate
+               // x.neg != y.neg, so we need to save y.neg before setting z.neg.
+               yneg := y.neg
+
                z.neg = x.neg
-               if x.neg == y.neg {
+               if x.neg == yneg {
                        // x + y == x + y
                        // (-x) + (-y) == -(x + y)
                        z.uadd(x, y)
@@ -1502,8 +1510,9 @@ func (z *Float) Sub(x, y *Float) *Float {
 
        if x.form == finite && y.form == finite {
                // x - y (common case)
+               yneg := y.neg
                z.neg = x.neg
-               if x.neg != y.neg {
+               if x.neg != yneg {
                        // x - (-y) == x + y
                        // (-x) - y == -(x + y)
                        z.uadd(x, y)
index 7d4bd312c9bd45f47026a2346709023d37ed8397..5fd49bb89462e56f67d1d8ba2d7dac0c3534b6fa 100644 (file)
@@ -1325,6 +1325,34 @@ func TestFloatAdd64(t *testing.T) {
        }
 }
 
+func TestIssue20490(t *testing.T) {
+       var tests = []struct {
+               a, b float64
+       }{
+               {4, 1},
+               {-4, 1},
+               {4, -1},
+               {-4, -1},
+       }
+
+       for _, test := range tests {
+               a, b := NewFloat(test.a), NewFloat(test.b)
+               diff := new(Float).Sub(a, b)
+               b.Sub(a, b)
+               if b.Cmp(diff) != 0 {
+                       t.Errorf("got %g - %g = %g; want %g\n", a, NewFloat(test.b), b, diff)
+               }
+
+               b = NewFloat(test.b)
+               sum := new(Float).Add(a, b)
+               b.Add(a, b)
+               if b.Cmp(sum) != 0 {
+                       t.Errorf("got %g + %g = %g; want %g\n", a, NewFloat(test.b), b, sum)
+               }
+
+       }
+}
+
 // TestFloatMul tests Float.Mul/Quo by comparing the result of a "manual"
 // multiplication/division of arguments represented by Bits values with the
 // respective Float multiplication/division for a variety of precisions