math/big: round x + (-x) to -0 for mode ToNegativeInf

Handling of sign bit as defined by IEEE 754-2008, section 6.3:

When the sum of two operands with opposite signs (or the difference of
two operands with like signs) is exactly zero, the sign of that sum (or
difference) shall be +0 in all rounding-direction attributes except
roundTowardNegative; under that attribute, the sign of an exact zero
sum (or difference) shall be −0. However, x+x = x−(−x) retains the same
sign as x even when x is zero.

This change handles the special case of Add/Sub resulting in exactly zero
when the rounding mode is ToNegativeInf setting the sign bit accordingly.

Fixes #25798

Change-Id: I4d0715fa3c3e4a3d8a4d7861dc1d6423c8b1c68c
Reviewed-on: https://go-review.googlesource.com/117495
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Brian Kessler 2018-06-08 11:48:18 -06:00 committed by Robert Griesemer
parent c359d759a7
commit d31cad7ca5
2 changed files with 31 additions and 2 deletions

View file

@ -1429,8 +1429,6 @@ func (x *Float) ucmp(y *Float) int {
// z's accuracy reports the result error relative to the exact (not rounded)
// result. Add panics with ErrNaN if x and y are infinities with opposite
// signs. The value of z is undefined in that case.
//
// BUG(gri) When rounding ToNegativeInf, the sign of Float values rounded to 0 is incorrect.
func (z *Float) Add(x, y *Float) *Float {
if debugFloat {
x.validate()
@ -1466,6 +1464,9 @@ func (z *Float) Add(x, y *Float) *Float {
z.usub(y, x)
}
}
if z.form == zero && z.mode == ToNegativeInf && z.acc == Exact {
z.neg = true
}
return z
}
@ -1530,6 +1531,9 @@ func (z *Float) Sub(x, y *Float) *Float {
z.usub(y, x)
}
}
if z.form == zero && z.mode == ToNegativeInf && z.acc == Exact {
z.neg = true
}
return z
}