Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

math: math.SmallestNonzeroFloat64 is not sufficiently precise, leading to unexpected results #44058

Closed
griesemer opened this issue Feb 2, 2021 · 7 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@griesemer
Copy link
Contributor

The compiler constant expression

math.SmallestNonzeroFloat64 / 2

gets printed as 5e-324 (program), but the exact computation of math.SmallestNonzeroFloat64 / 2 using math/big arithmetic followed by rounding results in 0 (program).

There's either an error with the rounding or constant arithmetic somewhere, or a mistake in my assumptions.

This affects a test case in types2/testdata/const1.src.

@griesemer griesemer added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Feb 2, 2021
@griesemer griesemer added this to the Go1.17 milestone Feb 2, 2021
@griesemer griesemer self-assigned this Feb 2, 2021
@dreamerjackson
Copy link
Contributor

i think it's a mistake, in golang compile, the math.SmallestNonzeroFloat64 / 2 will use big.Float to calculate multi-precision floating, and when transform to float64 the precision will loss, so the print will undefined.

and your example use big.Rat, it's different

@dreamerjackson
Copy link
Contributor

math.SmallestNonzeroFloat64 / 2 is a special example will rounding to math.SmallestNonzeroFloat64, the logic is here。change the types2/testdata/const1.src

func (x *Float) Float64() (float64, Accuracy) {
		if e < emin {
			// recompute precision
			p = mbits + 1 - emin + int(e)
			if p < 0 /* m <= 0.25 */ || p == 0 && x.mant.sticky(uint(len(x.mant))*_W-1) == 0 /* m == 0.5 */ {
				// underflow to ±0
				if x.neg {
					var z float64
					return -z, Above
				}
				return 0.0, Below
			}
			// otherwise, round up
			// We handle p == 0 explicitly because it's easy and because
			// Float.round doesn't support rounding to 0 bits of precision.
			if p == 0 {
				if x.neg {
					return -math.SmallestNonzeroFloat64, Below
				}
				return math.SmallestNonzeroFloat64, Above
			}
		}
}

@gopherbot
Copy link

Change https://golang.org/cl/288672 mentions this issue: math/big: fix SmallestNonzeroFloat64 const tesedata data

@griesemer
Copy link
Contributor Author

math.SmallestNonzeroFloat64 has the value 4.940656458412465441765687928682213723651e-324. This appears to not be sufficiently precise a representation (it's rounded up and a bit too large). If we add 3 more digits and go to 4.940656458412465441765687928682213723650598e-324 then dividing this number by 2 results in a float64 value that is 0, as expected (program).

@griesemer griesemer changed the title math/big: Float.Float64() may not round correctly for values near math.SmallestNonzeroFloat64 math: math.SmallestNonzeroFloat64 is not sufficiently precise, leading to unexpected results Apr 29, 2021
@griesemer griesemer added NeedsFix The path to resolution is known, but the work has not been done. and removed NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Apr 29, 2021
@griesemer
Copy link
Contributor Author

Program to compute accurate values to 512 bits.

@gopherbot
Copy link

Change https://golang.org/cl/315170 mentions this issue: math: increase precision of math.SmallestNonzeroFloat64

@gopherbot
Copy link

Change https://golang.org/cl/315969 mentions this issue: math: replace float32/64 extrema with exact expressions

gopherbot pushed a commit that referenced this issue May 3, 2021
Follow-up on https://golang.org/cl/315170.

Updates #44057.
Updates #44058.

Change-Id: I0b071e8ee7a1c97aae2436945cc9583cde3b40b0
Reviewed-on: https://go-review.googlesource.com/c/go/+/315969
Trust: Robert Griesemer <gri@golang.org>
Trust: Emmanuel Odeke <emmanuel@orijtech.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Russ Cox <rsc@golang.org>
@rsc rsc mentioned this issue Jun 10, 2021
83 tasks
@golang golang locked and limited conversation to collaborators May 1, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants