Skip to content

DIfferent behavior in Go 1.19/TinyGo when casting float with negative value to uint #3390

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

Closed
deadprogram opened this issue Jan 16, 2023 · 5 comments

Comments

@deadprogram
Copy link
Member

The following program produces different output in Go 1.19 vs. TinyGo:

package main

func main() {
	var vf1 float64 = -5.865784
	var vf2 float64 = 5.865784
	vu1 := uint32(vf1 * 10000)
	vu2 := uint32(vf2 * 10000)
	println(vu1, vu2)
}

Running this using Go 1.19 results in:

4294908639 58657

Running it using TinyGo results in:

0 58657
@aykevl
Copy link
Member

aykevl commented Jan 16, 2023

Interesting. In this case, I think the behavior is actually correct in both cases. Namely, the spec says the following:

In all non-constant conversions involving floating-point or complex values, if the result type cannot represent the value the conversion succeeds but the result value is implementation-dependent.

As the number -58657.84 cannot be represented as a uint32 (a negative value can never fit in an unsigned integer), the implementation is free to pick a number. Usually this is whatever the underlying architecture uses as a default value for out-of-range values but I believe we have some custom code for this in TinyGo because the native LLVM instruction results in undefined behavior on out-of-range values.
See: #276

CC @niaow

@dgryski
Copy link
Member

dgryski commented Jan 16, 2023

So converting to a signed int type first would be "safer" in this case rather than going directly from float64 to uint32?

@aykevl
Copy link
Member

aykevl commented Jan 16, 2023

Depends on what you want. If the value could be negative, converting to a int32 (or int64) first at least gives you a consistent result. But converting a negative float value to an unsigned integer will always be a "weird" value as it's out of range.

Here is a slightly more simplified version of the reproducer:

package main

func main() {
        var vf1 float64 = -5
        var vf2 float64 = 5
        println(uint32(vf1), uint32(vf2))
}

@hollowaykeanho
Copy link

hollowaykeanho commented Jan 20, 2023

UPDATE:

Sorry all. Please ignore my post here and its associated GitHub sent email.

I shouldn't be seeking 3rd-party validation over this petty matter. I will concentrate more on the standard libraries assimilations development (actual work) rather messing in the forum.

Regards,
Holloway

@deadprogram
Copy link
Member Author

Closing since this is undefined behavior. Thanks everyone!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants