mirror of
https://github.com/golang/go
synced 2024-11-18 04:04:49 -07:00
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 <alb.donizetti@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
673fdea5e7
commit
1948b7f806
@ -1439,8 +1439,16 @@ func (z *Float) Add(x, y *Float) *Float {
|
|||||||
|
|
||||||
if x.form == finite && y.form == finite {
|
if x.form == finite && y.form == finite {
|
||||||
// x + y (common case)
|
// 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
|
z.neg = x.neg
|
||||||
if x.neg == y.neg {
|
if x.neg == yneg {
|
||||||
// x + y == x + y
|
// x + y == x + y
|
||||||
// (-x) + (-y) == -(x + y)
|
// (-x) + (-y) == -(x + y)
|
||||||
z.uadd(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 {
|
if x.form == finite && y.form == finite {
|
||||||
// x - y (common case)
|
// x - y (common case)
|
||||||
|
yneg := y.neg
|
||||||
z.neg = x.neg
|
z.neg = x.neg
|
||||||
if x.neg != y.neg {
|
if x.neg != yneg {
|
||||||
// x - (-y) == x + y
|
// x - (-y) == x + y
|
||||||
// (-x) - y == -(x + y)
|
// (-x) - y == -(x + y)
|
||||||
z.uadd(x, y)
|
z.uadd(x, y)
|
||||||
|
@ -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"
|
// TestFloatMul tests Float.Mul/Quo by comparing the result of a "manual"
|
||||||
// multiplication/division of arguments represented by Bits values with the
|
// multiplication/division of arguments represented by Bits values with the
|
||||||
// respective Float multiplication/division for a variety of precisions
|
// respective Float multiplication/division for a variety of precisions
|
||||||
|
Loading…
Reference in New Issue
Block a user