Skip to content

Commit 498899e

Browse files
shogo82148gopherbot
authored andcommitted
math: fix portable FMA implementation when x*y ~ 0, x*y < 0 and z = 0
Adding zero usually does not change the original value. However, there is an exception with negative zero. (e.g. (-0) + (+0) = (+0)) This applies when x * y is negative and underflows. Fixes #73757 Change-Id: Ib7b54bdacd1dcfe3d392802ea35cdb4e989f9371 GitHub-Last-Rev: 30d7488 GitHub-Pull-Request: #73759 Reviewed-on: https://go-review.googlesource.com/c/go/+/673856 Auto-Submit: Keith Randall <khr@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Robert Griesemer <gri@google.com>
1 parent 2cde950 commit 498899e

File tree

2 files changed

+13
-1
lines changed

2 files changed

+13
-1
lines changed

src/math/all_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,6 +2126,11 @@ var fmaC = []struct{ x, y, z, want float64 }{
21262126
// Issue #61130
21272127
{-1, 1, 1, 0},
21282128
{1, 1, -1, 0},
2129+
2130+
// Issue #73757
2131+
{0x1p-1022, -0x1p-1022, 0, Copysign(0, -1)},
2132+
{Copysign(0, -1), 1, 0, 0},
2133+
{1, Copysign(0, -1), 0, 0},
21292134
}
21302135

21312136
var sqrt32 = []float32{

src/math/fma.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,16 @@ func FMA(x, y, z float64) float64 {
9696
bx, by, bz := Float64bits(x), Float64bits(y), Float64bits(z)
9797

9898
// Inf or NaN or zero involved. At most one rounding will occur.
99-
if x == 0.0 || y == 0.0 || z == 0.0 || bx&uvinf == uvinf || by&uvinf == uvinf {
99+
if x == 0.0 || y == 0.0 || bx&uvinf == uvinf || by&uvinf == uvinf {
100100
return x*y + z
101101
}
102+
// Handle z == 0.0 separately.
103+
// Adding zero usually does not change the original value.
104+
// However, there is an exception with negative zero. (e.g. (-0) + (+0) = (+0))
105+
// This applies when x * y is negative and underflows.
106+
if z == 0.0 {
107+
return x * y
108+
}
102109
// Handle non-finite z separately. Evaluating x*y+z where
103110
// x and y are finite, but z is infinite, should always result in z.
104111
if bz&uvinf == uvinf {

0 commit comments

Comments
 (0)