Pick a random number between 0 and n using a constant source of randomness

x86 machines with rdrand instruction, 10 bytes

BITS 64

_try_again:

 rdrand eax
jnc _try_again

 cmp eax, edi
ja _try_again

 ret

machine code

0FC7F0 73FB 39F8 77F7 C3

The input is in the register rdi and the output in rax.
This respects the SYS V AMD64 ABI so the code effectively implement a C function

unsigned int foo(unsigned int max); 

with 32-bit ints.

The instruction rdrand is described by Intel

RDRAND returns random numbers that are supplied by a cryptographically secure, deterministic random bit generator DRBG. The DRBG is designed to meet the NIST SP 800-90A standard.

Dealing with CSRNG it is implicit that the distribution is uniform, anyway, quoting the NIST SP 800-90A:

A random number is an instance of an unbiased random variable, that is, the output produced by a uniformly distributed random process.


The procedure generates a random number and if it is non-strictly greater than the input it is returned.
Otherwise, the process is reiterated.

Since eax is 32-bit, rdrand returns a number between 0 and 232-1, so for every n in [0, 232-1] the number of expected iterations is 232/(n+1) which is defined for all n in [0, 230).


Jelly, 7 6 bytes

⁴!!X%‘

Thanks to @JonathanAllan for golfing off 1 byte!

Cannot be run on TIO because (16!)! is a huge number.

How it works

⁴!!X%‘  Main link. Argument: n

⁴       Set the return value to 16.
 !!     Compute (16!)!.
   X    Pseudo-randomly choose an integer between 1 and (16!)!.
        Since (16!)! is evenly divisible by any k ≤ 2**30, it is evenly divisible
        by n+1.
    %‘  Take the result modulo n+1.

Mathematica, 29 bytes

Based on Dennis's Jelly answer.

RandomInteger[2*^9!-1]~Mod~#&

I wouldn't recommend actually running this. 2e9! is a pretty big number...

It turns out to be shortest to generate a huge number that is divisible by all possible inputs and the map the result to the required range with a simple modulo.

Rejection Sampling, 34 bytes

My old approach that led to somewhat more interesting code:

13!//.x_/;x>#:>RandomInteger[13!]&

Basic rejection sampling. We initialise the output to 13! (which is larger than the maximum input 230) and then repeatedly replace it with a random integer between 0 and 13! as long as the value is bigger than the input.