1
$\begingroup$

I have a robust RNG that generates random 32-bit (unsigned) ints. As is probably well known, for metropolis MC simulation, a random number between 0 and 1 is needed to determine acceptance/rejection of a move, so I need to convert my 32-bit int into a (double-precision) floating point value.

My question is what is best practice for converting my 32-bit int into a float? I think I have the following two options:

  • (double) getRandomNumber() / 4294967295 (2^32 - 1); range [0,1]
  • (double) getRandomNumber() / 4294967296 (2^32); range [0,1)

The first option seems straightforward, with a range of [0,1]. There would be 2147483648 values in the range [0,0.5) and 2147483648 values in the range (0.5, 1].

In the second option, we have a range of [0,1), and 0.5 is represented exactly among the 2^32 possible floats. There is symmetry in that 50% of the values are in the range [0, .49999999977], and the other 50% are in the range [0.5, .99999999977].

Are there details in the int->double conversion that I am missing? What's standard practice for a range for probabilistic simulations of this type? Is it [0,1], (0,1], [0,1), or (0,1)? Or am I splitting hairs over a trivial matter?

Note I've read that division is less efficient than multiplication, so I do intend to precompute the reciprocal and multiply by that value instead in my actual implementation.

$\endgroup$
3
  • $\begingroup$ The standard is to return a value in the range $[0,1)$: see c++'s en.cppreference.com/w/cpp/numeric/random/…. Also: compare the error from this "bias" with the Monte Carlo method's sampling error–assuming $\Theta(n^{-1/2})$ convergence, an error of $2^{-32}$ would only be detectable if you had on the order of $2^{64}$ samples. I'd also add that replacing divisions with multiplications by hand is a typical example of premature optimization–it is nowhere near expensive enough in typical code to worry about it. $\endgroup$
    – Kirill
    Jul 26, 2016 at 20:35
  • $\begingroup$ Thanks for the insight. Given the insignificance of the "bias," I will divide by 2^32 -1. Mainly because I must implement a getMaxRN() function which returns int, and I realized that 2^32 can't be represented by an int. $\endgroup$
    – bernie
    Jul 26, 2016 at 22:36
  • $\begingroup$ I just want to note that std::uniform_int_distribution returns a closed range, whereas std::uniform_real_distribution returns the half open range. $\endgroup$
    – bernie
    Jul 28, 2016 at 21:05

1 Answer 1

0
$\begingroup$

I think you're splitting hairs on something trivial. Maybe for a cryptographic RNG this detail might matter, but I'd be surprised if your choice here ever affected any result. For one thing, any bias of this size would only even be detectable if you generate something like 2^30 numbers in a go, which at that point you should be looking at using a longer period RNG sequence anyways.

I would just go with the [0,1] approach since getting exactly 0.5 could lead to some nasty bugs that would be hard to find later (part of the code uses <0.5 for reject/accept, other parts >0.5, for almost every random number this would still work but this bug would be something that would be hard to reproduce and only rear its head in the long (and therefore important) runs).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.