9

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.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
wheaties
  • 35,646
  • 15
  • 94
  • 131
  • y is -1? Is your OS a 32bits one, or a 64bits one? – VonC Nov 13 '14 at 14:18
  • To the guy that downvoted me, why the downvote? @VonC 64 bit. – wheaties Nov 13 '14 at 14:20
  • @VonC I'll be. I bet we've set up this Varnish to run as 32 bit! – wheaties Nov 13 '14 at 14:24
  • What would you want `y` to be if not -1? You want to assert that `x == y` after the conversion and have an error/panic if it is not? – ANisus Nov 13 '14 at 14:44
  • @ANisus A random number generator returns a discrete set of bits with certain random properties. In this case there are 64 bits of them. I would like to be able to take those 64 bits and use them as an `int64`. I do not want, as I said above, a straight numeric conversion. – wheaties Nov 13 '14 at 14:46

3 Answers3

16

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
ANisus
  • 74,460
  • 29
  • 162
  • 158
  • I'm kind of at a loss of which one of you two to give the answer. You correctly pointed out that I was mis-interpreting the -1 to be something it was not. However, that mis-interpritation was a direct result of running Varnish in a 32-bit setting. I think I need to give it to VonC but wish I could give you more +1. – wheaties Nov 13 '14 at 14:55
  • 18446744073709551615 is 0xffffffffffffffff – Paul Hankin Nov 16 '14 at 23:26
  • @Anonymous: Thanks for noticing. Added the missing F's – ANisus Nov 17 '14 at 07:20
6

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;

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Running outside of Varnish on a 64 bit machine I'm still seeing it. It's not causing an overflow panic but it is returning `-1` which pretty much destroys all the randomness of the bits. – wheaties Nov 13 '14 at 14:41
  • @wheaties ok, I was mentioning that possibility after reading http://stackoverflow.com/a/16458451/6309 – VonC Nov 13 '14 at 14:48
  • I'm kind of at a loss of which one of you two give the answer to. You actually pointed me to the fact that I was running Varnish in a 32 bit set up which would indicate it would always come out -1 while ANisus stated the obvious, I was just drawing the wrong conclusion based upon the experience on the 32 bit system. – wheaties Nov 13 '14 at 14:54
  • @wheaties I have complete ANisus's answer with an playground example. – VonC Nov 13 '14 at 15:03
  • Did the question change? I don't see how this answer has anything to do with the question. – Paul Hankin Nov 16 '14 at 23:27
0

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.

PassKit
  • 12,231
  • 5
  • 57
  • 75