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

go/types: misleading error message in const expression #11825

Closed
griesemer opened this issue Jul 22, 2015 · 7 comments
Closed

go/types: misleading error message in const expression #11825

griesemer opened this issue Jul 22, 2015 · 7 comments
Assignees
Milestone

Comments

@griesemer
Copy link
Contributor

@griesemer griesemer commented Jul 22, 2015

package a
var a = 1e20/complex64(1e-20)

gotype reports:

x.go:2:9: 1e20 (constant 15474250801184809498242605942063297429153775616/1547425 of type complex64) overflows complex64

The culprit is not 1e20. The error message needs to be investigated.

@griesemer griesemer self-assigned this Jul 22, 2015
@griesemer griesemer added this to the Go1.6 milestone Jul 22, 2015
@griesemer
Copy link
Contributor Author

@griesemer griesemer commented Jul 31, 2015

There may be a more serious underlying problem. For a test case x.src:

package a
const a = 1e15/complex64(1e-15)
const _ = trace(a)

we get

$ go test -run=Check -files=x.src -list
x.src:3:17: a (constant 1000000015047466219876688855040 of type complex64)

that is the traced constant value is not exact. However, in http://play.golang.org/p/1nxEHRZf5P we get the exact result

+1.000000e+030

Suspicion: Premature rounding after unary/binary operations.

Loading

@griesemer
Copy link
Contributor Author

@griesemer griesemer commented Jul 31, 2015

Simpler:

package a
const a = float32(1e30)
const _ = trace(a)

produces

$ go test -run=Check -files=x.src -list
x.src:3:17: a (constant 1000000015047466219876688855040 of type float32)

vs http://play.golang.org/p/jYgihTQe8f

+1.000000e+030

Loading

@griesemer griesemer added this to the Go1.6Early milestone Jul 31, 2015
@griesemer griesemer removed this from the Go1.6 milestone Jul 31, 2015
@griesemer
Copy link
Contributor Author

@griesemer griesemer commented Aug 25, 2015

Correction: With the latest gotype, go/types, we get:

package a
var a = 1e20/complex64(1e-20)

gotype reports:

x.src:2:9: 1e20 / complex64(1e-20) (constant 15474250801184809498242605942063297429153775616/1547425 of type complex64) overflows complex64

which is a) the correct expression, and b) likely the correct value (it's 1.0000000517753564e+40, or 1e40 after rounding to 24bits).

Similarly,

package a
const a = 1e15/complex64(1e-15)
const _ = trace(a)

prints

x.src:3:17: a (constant 1000000015047466219876688855040 of type complex64)

which is approx. 1e30. Per the spec (http://tip.golang.org/ref/spec#Conversions):

... x is a floating-point constant, T is a floating-point type, and x is representable by a value of type T after rounding using IEEE 754 round-to-even rules. The constant T(x) is the rounded value.

Thus internally, we need to continue in full precision (or in case of go/types, exact) after the intermediate value was rounded to float32 (in this case). Consequently, we get spurious values.

Should decide if error messages should report in a different more readable format.

Loading

@griesemer griesemer added this to the Go1.6 milestone Aug 25, 2015
@griesemer griesemer removed this from the Go1.6Early milestone Aug 25, 2015
@griesemer
Copy link
Contributor Author

@griesemer griesemer commented Aug 25, 2015

Loading

@rsc
Copy link
Contributor

@rsc rsc commented Nov 30, 2015

Might still be worth fixing, if easy.

Loading

@griesemer
Copy link
Contributor Author

@griesemer griesemer commented Dec 10, 2015

With the pending CL https://go-review.googlesource.com/#/c/17360/ we now get better error messages. For the original example we get:

foo.go:2:9: 1e20 / complex64(1e-20) (constant (1e+40 + 0i) of type complex64) overflows complex64

Loading

@griesemer
Copy link
Contributor Author

@griesemer griesemer commented Dec 10, 2015

This appears to be fixed (or the error was incorrectly analyzed). For the following program:
http://play.golang.org/p/BSaLgO57dT
we get with cmd/compile (playground and command line):

-1.1102230246251565e-16 false
0 true
(1e+30+0i)
1e+30
(1e+30+0i)

The corresponding test case for go/types is (the trace built-in is available for testing only):

package main

const (
    e           = 1.0 / (1.0 << 53)
    a           = 1.0 + e
    a64 float64 = 1.0 + e

    x = 1e15 / complex64(1e-15)
    y = 1e15 / 1e-15
    z = complex64(1e15) / complex64(1e-15)
)

func main() {
    trace(1.0-a, a == 1.0)
    trace(1.0-a64, a64 == 1.0)
    trace(x)
    trace(y)
    trace(z)
}

With the current go/types (uses big.Rat for constant arithmetic) we get:

$ go test -run=Check -files=/Users/gri/tmp/f.go -list
f.go:14:8: 1.0 - a (untyped float constant -1/9007199254740992)
f.go:14:15: a == 1.0 (untyped bool constant false)
f.go:15:8: 1.0 - a64 (constant 0 of type float64)
f.go:15:17: a64 == 1.0 (untyped bool constant true)
f.go:16:8: x (constant 1000000015047466219876688855040 of type complex64)
f.go:17:8: y (untyped float constant 1000000000000000000000000000000)
f.go:18:8: z (constant 1000000015047466219876688855040 of type complex64)

-1/9007199254740992 is -1.1102230246251565404236316680908203125 × 10^-16 which is -1.11022e-16 or -2**-53 which is correct (http://www.wolframalpha.com/input/?i=-1%2F9007199254740992).
The discrepancies for line 16 and 18 are identical and are due to the fact that 1e-15 after truncation to complex64 is actually slightly smaller than 1e-15 resulting in a slightly larger result.

With the pending CL https://go-review.googlesource.com/#/c/17360/ (uses big.Float for constant arithmetic):

$ go test -run=Check -files=/Users/gri/tmp/f.go -list
f.go:14:8: 1.0 - a (untyped float constant -1.11022e-16)
f.go:14:15: a == 1.0 (untyped bool constant false)
f.go:15:8: 1.0 - a64 (constant 0 of type float64)
f.go:15:17: a64 == 1.0 (untyped bool constant true)
f.go:16:8: x (constant (1e+30 + 0i) of type complex64)
f.go:17:8: y (untyped float constant 1e+30)
f.go:18:8: z (constant (1e+30 + 0i) of type complex64)

matching cmd/compile output exactly.

Or in other words: The incorrect expression in the error message reported in the beginning of this issue was fixed. The other discrepancies in output are due to the fact that go/types, when based on rational arithmetic, is doing exact (algebraic) math (no rounding). When using go/types based on floating-point arithmetic (doing rounding), we get the same result as cmd/compile.

Closing as resolved.

Loading

@griesemer griesemer closed this Dec 10, 2015
@golang golang locked and limited conversation to collaborators Dec 14, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants