-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
cmd/gc: inaccurate ideal float comparison #2789
Labels
Milestone
Comments
"Numeric constants represent values of arbitrary precision and do not overflow." http://golang.org/doc/go_spec.html#Constants The compiler evaluates (0.1+0.2) using arbitrary precision arithmetic and then converts the result to IEEE 754 64-bit floating-point arithmetic. At runtime, the executable program evaluates (i+0.2) using IEEE 754 64-bit floating-point arithmetic. package main import ( "fmt" "math" ) func main() { i := 0.1 fmt.Println((i + 0.2) == (0.1 + 0.2)) fmt.Println(math.Float64bits(i+0.2), math.Float64bits(0.1+0.2)) } Output: false 4599075939470750516 4599075939470750515 |
A simpler case is: package main const b = 0.1+0.2 < 0.3 func main() { println(b) } I would like to understand whether the compiler's internal representation is making a mistake here or this is just an inevitable rounding issue. It seems like we should be able to do better than this. Remy, are you interested in this? Russ Labels changed: added priority-go1, removed priority-triage. Owner changed to @rsc. Status changed to Accepted. |
We should probably clarify the meaning of ideal constants in the spec before. Depending on the choice, there will be natural compiler representations of these: 1. "A numeric constant represent arbitrary precision integers. A conforming compiler may use rounded representations for non-integral constants. The chosen representation must at least represent exactly binary floating-point values with twice the bit count of machine types." In 1., I suppose the current implementation is conformant. It uses binary floating-point, with multi-precision mantissa, and rounds a/b at 128 bits. With this spec, the result of "0.1 + 0.2 == 0.3" is undefined, and "0.1 * 10 == 1" is allowed to be always false. What does the current spec says about (1.0e999 - (1.0e999-1)) ? 2. "A numeric constant represent arbitrary precision integers and decimal numbers. It must exactly represent floating-point literals, however a conformant compiler may choose to round the results of division of such constants". In 2., the natural representation would be a multiprecision mantissa and a base 10 exponent in a reasonable range. Then "0.1 + 0.2 == 0.3" would be somewhat guaranteed to be true, but "(1.0 / 49.0) * 49.0" is not guaranteed. 3. "A numeric constant represent exactly arbitrary precision integers, floating-point literals as well as the result of operations between them." In 3. the appropriate representation would probably be rational numbers, something like struct Mprat { Mpint numerator, denominator; }; I think 3 is too much. 2 is reasonable but would require quite many changes to compilers, and 1 is reasonable if the spec is clarified. |
It is too late to change the language spec at this point. #1 is a good summary of what the spec says (or what we mean it to say). I understand that it is possible that 0.1 + 0.2 != 0.3 according to the spec; however, I would like to understand if it is truly an implication of using the numbers that gc does (they are something like 700-bit precision) or just a bug in gc's rounding. There have been significant bugs (millions of ULPs) in gc's rounding before. I just remembered that the raw constants can be read out of the .6 files, and in this case it is working correctly, so it's not a gc bug (hence closing as Unfortunate). Remy, if you believe the spec is unclear as far as #1, could you send a CL clarifying the language? Thanks. Russ Status changed to Unfortunate. |
I guess (but can't really tell right now) the rounding is correct. Maybe a workaround would be to use an intermediate precision when it comes to ideal floatingpoint comparison? It wouldn't eliminate the problem but maybe give less surprising results. For example, in mpcmpfltflt we could say ideal equality would be defined as "truncations to some number of bits, maybe half the total chosen precision, are equal". |
This issue was closed by revision 9126c65. Status changed to Fixed. |
This issue was closed.
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
by fan.howard:
The text was updated successfully, but these errors were encountered: