Question in Converting float64 to uint64

390 views
Skip to first unread message

Xie Yuchen

unread,
Oct 25, 2023, 7:25:40 AM10/25/23
to golang-nuts
Hi Guys, recently, I've been learning the number types conversion. I learned about the ieee 754 round to even when golang converts from uint64 to float64.

However, when I want to convert the float64 to uint64 back, there is a different between functions: `math.Float64Bits` and use `uint64(f)`.

Here is the code example: https://go.dev/play/p/Au0YCVKYas8

The output is:
```
4895412794951729152
1111111111111111111111111111111111111111111111111111111111111111
1.8446744073709552e+19
4895412794951729152
4895412794951729152
9223372036854775808
```
The 4895412794951729152 is output by math.Float64Bits and the value 9223372036854775808 is directly begot from `uint64(f)`.

I am still confusing where the 9223372036854775808 comes from. Could you kindly help me if you have some ideas?

Eli Lindsey

unread,
Oct 25, 2023, 10:39:17 AM10/25/23
to Xie Yuchen, golang-nuts
Float64Bits preserves the underlying representation. The numeric value of the uint64 it returns has little significance. You’d typically use it when serializing floats, when wanting to make manual changes to the float’s representation, and so on.

uint64(f) cares about preserving the numeric value. As documented in the spec it will truncate towards zero and convert, preserving the same numeric value.

Your particular case however is hitting platform-specific behavior. This simplified version (https://go.dev/play/p/GiQ2kuxol1d) will print 9223372036854775808 for u on x86, but 18446744073709551615 on arm. This is an area that frequently lands in undefined behavior in other languages.

For what it's worth, I don’t think the spec is particularly clear on this point.

From the spec:
> 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.

From stdlib math docs:
> Max is the largest finite value representable by the type.

To me that would suggest that converting a float64 of MaxUint64 to a uint64 would result in MaxUint64 across implementations, but that doesn’t appear true in practice.

-eli

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/eaa5da30-5545-47c5-96aa-a3b0a2eeb1e4n%40googlegroups.com.

j2gg0s

unread,
Oct 25, 2023, 11:11:00 AM10/25/23
to golang-nuts
Just my guess:
- when use IEE754, 18446744073709551615 will be actual stored as 18446744073709551616 (> 2<<64)
- so uint64(float64(18446744073709551615)) is overflow and undefined

Code:
// true
fmt.Println(uint64(float64(18446742974197923840)) == uint64(18446742974197923840))
// cannot convert float64(18446744073709551615) (constant 18446744073709551616 of type float64) to type uint64
fmt.Println(uint64(float64(18446744073709551615)))
Reply all
Reply to author
Forward
0 new messages