uint(-5.0), where parameter is a float64, = 18446744073709551611?

112 Views Asked by At

In the Tour of Go, step 13, I changed a bit the script

package main

import (
    "fmt"
    "math"
)

func main() {
    var x, y int = 3, 4
    var f float64 = math.Sqrt(float64(x*x + y*y))
    var z uint  = uint(f)
    fmt.Println(x, y, z, f)
}

This returns: 3 4 5 5, fine.

But when I do this change: negating f:

func main() {
    var x, y int = 3, 4
    var f float64 = - math.Sqrt(float64(x*x + y*y))
    var z uint  = uint(f)
    fmt.Println(x, y, z, f)
}

It responds: 3 4 18446744073709551611 -5

Why does the -5.0 being converted to 18446744073709551611 by the uint method?

Isn't there something - an algorithm? - trying to check what it is doing beneath?
It's like the uint method was brutally casting at binary level from float with mantissa and exponent to an integer?

What is happening?

enter image description here

If I am misled, and that methods uint aren't conversion functions like I believed,
but cast methods like you could find (uint)f in C,
what is the conversion function that ensure that:

uint z = anotherFunction(any float64)

will return the positive integer value of that float number?

1

There are 1 best solutions below

7
icza On

Value of f is a negative number: -5.0. What would you expect when you convert this to a value of an unsigned type? Unsigned types have a valid range / representation where there's no room for -5.

Go (like most other languages) uses 2's complement to represent integers. When you convert a signed integer to an unsigned integer, the representation (binary data in memory) is kept, but the number will be interpreted differently.

In general, when converting a negative signed value to an unsigned value, you can calculate the result using:

result: MAX_VALUE + x + 1 = MAX_VALUE - ABS(x) + 1

So for example when converting -5 of type int8 to uint8, the result will be:

255 - 5 + 1 = 251

The same goes for converting -5 of type int64 to uint64:

18446744073709551615 - 5 + 1 = 18446744073709551611

(Note: size of int and uint is platform dependent, on the Go Playground it is of size 64-bit, same as int64 and uint64.)

The last missing piece: your f is of type float64. Converting float64 to integer from Spec: Conversions: Conversions between numeric types:

For the conversion of non-constant numeric values, the following rules apply:

[...]

  1. When converting a floating-point number to an integer, the fraction is discarded (truncation towards zero).

So -5.0 is converted to -5, then the above algorithm can be used how this will look like when interpreted as a value of type uint.