Skip to content

Commit d31cad7

Browse files
bmkesslergriesemer
authored andcommitted
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent c359d75 commit d31cad7

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

src/math/big/float.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,8 +1429,6 @@ func (x *Float) ucmp(y *Float) int {
14291429
// z's accuracy reports the result error relative to the exact (not rounded)
14301430
// result. Add panics with ErrNaN if x and y are infinities with opposite
14311431
// signs. The value of z is undefined in that case.
1432-
//
1433-
// BUG(gri) When rounding ToNegativeInf, the sign of Float values rounded to 0 is incorrect.
14341432
func (z *Float) Add(x, y *Float) *Float {
14351433
if debugFloat {
14361434
x.validate()
@@ -1466,6 +1464,9 @@ func (z *Float) Add(x, y *Float) *Float {
14661464
z.usub(y, x)
14671465
}
14681466
}
1467+
if z.form == zero && z.mode == ToNegativeInf && z.acc == Exact {
1468+
z.neg = true
1469+
}
14691470
return z
14701471
}
14711472

@@ -1530,6 +1531,9 @@ func (z *Float) Sub(x, y *Float) *Float {
15301531
z.usub(y, x)
15311532
}
15321533
}
1534+
if z.form == zero && z.mode == ToNegativeInf && z.acc == Exact {
1535+
z.neg = true
1536+
}
15331537
return z
15341538
}
15351539

src/math/big/float_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,31 @@ func TestFloatAdd(t *testing.T) {
12581258
}
12591259
}
12601260

1261+
// TestFloatAddRoundZero tests Float.Add/Sub rounding when the result is exactly zero.
1262+
// x + (-x) or x - x for non-zero x should be +0 in all cases except when
1263+
// the rounding mode is ToNegativeInf in which case it should be -0.
1264+
func TestFloatAddRoundZero(t *testing.T) {
1265+
for _, mode := range [...]RoundingMode{ToNearestEven, ToNearestAway, ToZero, AwayFromZero, ToPositiveInf, ToNegativeInf} {
1266+
x := NewFloat(5.0)
1267+
y := new(Float).Neg(x)
1268+
want := NewFloat(0.0)
1269+
if mode == ToNegativeInf {
1270+
want.Neg(want)
1271+
}
1272+
got := new(Float).SetMode(mode)
1273+
got.Add(x, y)
1274+
if got.Cmp(want) != 0 || got.neg != (mode == ToNegativeInf) {
1275+
t.Errorf("%s:\n\t %v\n\t+ %v\n\t= %v\n\twant %v",
1276+
mode, x, y, got, want)
1277+
}
1278+
got.Sub(x, x)
1279+
if got.Cmp(want) != 0 || got.neg != (mode == ToNegativeInf) {
1280+
t.Errorf("%v:\n\t %v\n\t- %v\n\t= %v\n\twant %v",
1281+
mode, x, x, got, want)
1282+
}
1283+
}
1284+
}
1285+
12611286
// TestFloatAdd32 tests that Float.Add/Sub of numbers with
12621287
// 24bit mantissa behaves like float32 addition/subtraction
12631288
// (excluding denormal numbers).

0 commit comments

Comments
 (0)