Skip to content

Commit 1948b7f

Browse files
committed
math/big: fix Add, Sub when receiver aliases 2nd operand
Fixes #20490 Change-Id: I9cfa604f9ff94df779cb9b4cbbd706258fc473ac Reviewed-on: https://go-review.googlesource.com/44150 Run-TryBot: Alberto Donizetti <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 673fdea commit 1948b7f

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

src/math/big/float.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,8 +1439,16 @@ func (z *Float) Add(x, y *Float) *Float {
14391439

14401440
if x.form == finite && y.form == finite {
14411441
// x + y (common case)
1442+
1443+
// Below we set z.neg = x.neg, and when z aliases y this will
1444+
// change the y operand's sign. This is fine, because if an
1445+
// operand aliases the receiver it'll be overwritten, but we still
1446+
// want the original x.neg and y.neg values when we evaluate
1447+
// x.neg != y.neg, so we need to save y.neg before setting z.neg.
1448+
yneg := y.neg
1449+
14421450
z.neg = x.neg
1443-
if x.neg == y.neg {
1451+
if x.neg == yneg {
14441452
// x + y == x + y
14451453
// (-x) + (-y) == -(x + y)
14461454
z.uadd(x, y)
@@ -1502,8 +1510,9 @@ func (z *Float) Sub(x, y *Float) *Float {
15021510

15031511
if x.form == finite && y.form == finite {
15041512
// x - y (common case)
1513+
yneg := y.neg
15051514
z.neg = x.neg
1506-
if x.neg != y.neg {
1515+
if x.neg != yneg {
15071516
// x - (-y) == x + y
15081517
// (-x) - y == -(x + y)
15091518
z.uadd(x, y)

src/math/big/float_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,34 @@ func TestFloatAdd64(t *testing.T) {
13251325
}
13261326
}
13271327

1328+
func TestIssue20490(t *testing.T) {
1329+
var tests = []struct {
1330+
a, b float64
1331+
}{
1332+
{4, 1},
1333+
{-4, 1},
1334+
{4, -1},
1335+
{-4, -1},
1336+
}
1337+
1338+
for _, test := range tests {
1339+
a, b := NewFloat(test.a), NewFloat(test.b)
1340+
diff := new(Float).Sub(a, b)
1341+
b.Sub(a, b)
1342+
if b.Cmp(diff) != 0 {
1343+
t.Errorf("got %g - %g = %g; want %g\n", a, NewFloat(test.b), b, diff)
1344+
}
1345+
1346+
b = NewFloat(test.b)
1347+
sum := new(Float).Add(a, b)
1348+
b.Add(a, b)
1349+
if b.Cmp(sum) != 0 {
1350+
t.Errorf("got %g + %g = %g; want %g\n", a, NewFloat(test.b), b, sum)
1351+
}
1352+
1353+
}
1354+
}
1355+
13281356
// TestFloatMul tests Float.Mul/Quo by comparing the result of a "manual"
13291357
// multiplication/division of arguments represented by Bits values with the
13301358
// respective Float multiplication/division for a variety of precisions

0 commit comments

Comments
 (0)