Convert uint64 to int64 without loss of information

11.1k views Asked by At

The problem with the following code:

var x uint64 = 18446744073709551615
var y int64 = int64(x)

is that y is -1. Without loss of information, is the only way to convert between these two number types to use an encoder and decoder?

buff bytes.Buffer
Encoder(buff).encode(x)
Decoder(buff).decode(y)

Note, I am not attempting a straight numeric conversion in your typical case. I am more concerned with maintaining the statistical properties of a random number generator.

3

There are 3 answers

5
VonC On BEST ANSWER

Seeing -1 would be consistent with a process running as 32bits.

See for instance the Go1.1 release notes (which introduced uint64)

x := ^uint32(0) // x is 0xffffffff
i := int(x)     // i is -1 on 32-bit systems, 0xffffffff on 64-bit
fmt.Println(i)

Using fmt.Printf("%b\n", y) can help to see what is going on (see ANisus' answer)

As it turned out, the OP wheaties confirms (in the comments) it was run initially in 32 bits (hence this answer), but then realize 18446744073709551615 is 0xffffffffffffffff (-1) anyway: see ANisusanswer;

3
ANisus On

Your conversion does not lose any information in the conversion. All the bits will be untouched. It is just that:

uint64(18446744073709551615) = 0xFFFFFFFFFFFFFFFF
int64(-1)                    = 0xFFFFFFFFFFFFFFFF

Try:

var x uint64 = 18446744073709551615 - 3

and you will have y = -4.


For instance: playground

var x uint64 = 18446744073709551615 - 3
var y int64 = int64(x)
fmt.Printf("%b\n", x)
fmt.Printf("%b or %d\n", y, y)

Output:

1111111111111111111111111111111111111111111111111111111111111100
-100 or -4
0
PassKit On

The types uint64 and int64 can both represent 2^64 discrete integer values.

The difference between the two is that uint64 holds only positive integers (0 thru 2^64-1), where as int64 holds both negative and positive integers using 1 bit to hold the sign (-2^63 thru 2^63-1).

As others have said, if your generator is producing 0xffffffffffffffff, uint64 will represent this as the raw integer (18,446,744,073,709,551,615) whereas int64 will interpret the two's complement value and return -1.