Skip to content

Commit

Permalink
math: increase precision of math.SmallestNonzeroFloat64
Browse files Browse the repository at this point in the history
The original value was rounded too early, which lead to the
surprising behavior that float64(math.SmallestNonzeroFloat64 / 2)
wasn't 0. That is, the exact compile-time computation of
math.SmallestNonzeroFloat64 / 2 resulted in a value that was
rounded up when converting to float64. To address this, added 3
more digits to the mantissa, ending in a 0.

While at it, also slightly increased the precision of MaxFloat64
to end in a 0.

Computed exact values via https://play.golang.org/p/yt4KTpIx_wP.

Added a test to verify expected behavior.

In contrast to the other (irrational) constants, expanding these
extreme values to more digits is unlikely to be important as they
are not going to appear in numeric computations except for tests
verifying their correctness (as is the case here).

Re-enabled a disabled test in go/types and types2.

Updates #44057.
Fixes #44058.

Change-Id: I8f363155e02331354e929beabe993c8d8de75646
Reviewed-on: https://go-review.googlesource.com/c/go/+/315170
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
  • Loading branch information
griesemer committed Apr 30, 2021
1 parent 02ab8d1 commit 3498027
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 12 deletions.
2 changes: 2 additions & 0 deletions api/except.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pkg encoding/json, method (*RawMessage) MarshalJSON() ([]uint8, error)
pkg math, const MaxFloat64 = 1.79769e+308 // 179769313486231570814527423731704356798100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math, const SmallestNonzeroFloat64 = 4.94066e-324 // 4940656458412465441765687928682213723651/1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math/big, const MaxBase = 36
pkg math/big, type Word uintptr
pkg net, func ListenUnixgram(string, *UnixAddr) (*UDPConn, error)
Expand Down
10 changes: 5 additions & 5 deletions src/cmd/compile/internal/types2/testdata/check/const1.src
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

package const1

import "math"

const(
mi = ^int(0)
mu = ^uint(0)
Expand Down Expand Up @@ -48,7 +50,7 @@ const (
// without overflow. For now we match the compiler.
// See also issue #44057.
// smallestFloat64 = 1.0 / (1<<(1023 - 1 + 52))
smallestFloat64 = 4.940656458412465441765687928682213723651e-324
smallestFloat64 = math.SmallestNonzeroFloat64
)

const (
Expand All @@ -63,7 +65,7 @@ const (
// without overflow. For now we match the compiler.
// See also issue #44057.
// maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
maxFloat64 = 1.797693134862315708145274237317043567981e+308
maxFloat64 = math.MaxFloat64
)

const (
Expand Down Expand Up @@ -281,9 +283,7 @@ const (
_ = assert(float64(smallestFloat32) == smallestFloat32)
_ = assert(float64(smallestFloat32/2) == smallestFloat32/2)
_ = assert(float64(smallestFloat64) == smallestFloat64)
// TODO(gri) With the change to the declaration of smallestFloat64
// this now fails to be true. See issue #44058.
// _ = assert(float64(smallestFloat64/2) == 0)
_ = assert(float64(smallestFloat64/2) == 0)
)

const (
Expand Down
10 changes: 5 additions & 5 deletions src/go/types/testdata/check/const1.src
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

package const1

import "math"

const(
mi = ^int(0)
mu = ^uint(0)
Expand Down Expand Up @@ -48,7 +50,7 @@ const (
// without overflow. For now we match the compiler.
// See also issue #44057.
// smallestFloat64 = 1.0 / (1<<(1023 - 1 + 52))
smallestFloat64 = 4.940656458412465441765687928682213723651e-324
smallestFloat64 = math.SmallestNonzeroFloat64
)

const (
Expand All @@ -63,7 +65,7 @@ const (
// without overflow. For now we match the compiler.
// See also issue #44057.
// maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
maxFloat64 = 1.797693134862315708145274237317043567981e+308
maxFloat64 = math.MaxFloat64
)

const (
Expand Down Expand Up @@ -281,9 +283,7 @@ const (
_ = assert(float64(smallestFloat32) == smallestFloat32)
_ = assert(float64(smallestFloat32/2) == smallestFloat32/2)
_ = assert(float64(smallestFloat64) == smallestFloat64)
// TODO(gri) With the change to the declaration of smallestFloat64
// this now fails to be true. See issue #44058.
// _ = assert(float64(smallestFloat64/2) == 0)
_ = assert(float64(smallestFloat64/2) == 0)
)

const (
Expand Down
9 changes: 9 additions & 0 deletions src/math/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3196,6 +3196,15 @@ func TestFloatMinMax(t *testing.T) {
}
}

func TestFloatMinima(t *testing.T) {
if q := float32(SmallestNonzeroFloat32 / 2); q != 0 {
t.Errorf("float32(SmallestNonzeroFloat32 / 2) = %g, want 0", q)
}
if q := float64(SmallestNonzeroFloat64 / 2); q != 0 {
t.Errorf("float64(SmallestNonzeroFloat64 / 2) = %g, want 0", q)
}
}

var indirectSqrt = Sqrt

// TestFloat32Sqrt checks the correctness of the float32 square root optimization result.
Expand Down
4 changes: 2 additions & 2 deletions src/math/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const (
MaxFloat32 = 3.40282346638528859811704183484516925440e+38 // 2**127 * (2**24 - 1) / 2**23
SmallestNonzeroFloat32 = 1.401298464324817070923729583289916131280e-45 // 1 / 2**(127 - 1 + 23)

MaxFloat64 = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
SmallestNonzeroFloat64 = 4.940656458412465441765687928682213723651e-324 // 1 / 2**(1023 - 1 + 52)
MaxFloat64 = 1.79769313486231570814527423731704356798070e+308 // 2**1023 * (2**53 - 1) / 2**52
SmallestNonzeroFloat64 = 4.9406564584124654417656879286822137236505980e-324 // 1 / 2**(1023 - 1 + 52)
)

// Integer limit values.
Expand Down

0 comments on commit 3498027

Please sign in to comment.