Home > OS >  Why can't you store the minimum value of int64 into a uint64?
Why can't you store the minimum value of int64 into a uint64?

Time:10-25

In theory an int64 fits in a uint64, of course their numeric values will be different due to the first bit being reserved for the sign on int64, however why can't I do this conversion? it seems valid to me

import (
    "fmt"
    "math"
)

func main() {
    var randomNum uint64 = math.MinInt64
    fmt.Println(randomNum)
}

Here math.MinInt64 is -9223372036854775808, technically a number that fits in 63 bits plus sign.

I'm mainly looking into this since I want to convert 4 bytes back into a int64 with proper sign, but so far I only have seen functions that return uint64

binary.LittleEndian.Uint64(bytesArrays[0:4])

CodePudding user response:

An int64 fits does fit in a uint64, but that's not what the code in the question does. The code assigns the constant math.MinInt64 to the uint64 variable randomNum. The compiler reports an error because the constant is not representable by a uint64.

Assign to a variable first so that the rules for constants do not apply:

x := int64(math.MinInt64)
var randomNum = uint64(x)
fmt.Println(randomNum)

CodePudding user response:

The reason why this "conversion" doesn't work, is because there is no conversion in your program. Assignment does not implicitly perform conversion (except for interface types).

See the assignability rules that govern assignment of constant values:

A value x is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:

  • x's type is identical to T.
  • ...
  • x is an untyped constant representable by a value of type T.

In this case, math.MinInt64 is an untyped constant, but it is not representable by value of type uint64, because it is defined as so:

uint64 the set of all unsigned 64-bit integers (0 to 18446744073709551615)

Conversion between negative 64 bit integers and unsigned 64 bit integers is possible, but you need a genuine conversion for that. Yet still, you can't convert the constant value directly, because of a familiar rule:

A constant value x can be converted to type T if x is representable by a value of T.

So, the correct way is to first assign the number to a non-constant value:

x := int64(math.MinInt64)
y := uint64(x)
fmt.Println(y)

Playground link

CodePudding user response:

Who says you can't? Okay, the compiler says that, sort of. But the compiler means that you can't put the value -9223372036854775808 into a uint64 variable, which is true; you need to put the bit pattern that, as an int64, represents -9223372036854775808, but representing the value it would be seen as a uint64 into the uint64:

var randomNum uint64 = math.MinInt64   math.MaxUint64   1

which works fine—or of course do what GastroHealth showed.

I'm mainly looking into this since I want to convert [8] bytes back into a int64 with proper sign, but so far I only have seen functions that return uint64 (such as binary.LittleEndian.Uint64).

We do the obvious:

signed := int64(v ^ 0x8000000000000000 - 0x8000000000000000)

(Well, it's obvious once you've seen it a few times.)

See a complete example here (I used big-endian, I like it better for human use). Note that you can just do signed := int64(v) here; the flip-and-subtract trick is good as an expression where you don't already have a variable.

  •  Tags:  
  • go
  • Related