# Generating 64-bit Random Numbers in a Given Range

There are good standard ways of generating 32-bit random numbers. If you need something really simple, it is possible for example to generate decent random numbers with a Linear Congruential Random Number Generator:

```class KxuLCRand
{
public:
KxuLCRand( u32 seed = 555 ) { setSeed( seed ); }
void setSeed( u32 seed ) { if ( !seed ) seed = 0x333; mState = seed | 0x1; }
u32 getRandom() { mState *= 69069; return mState; }

private:
u32 mState;
};
```

For generators for better statistical properties – such as for encryption or compression – you could use something like a Mersenne Twister. While in principle these generators could be written to generate 64-bit results natively, for efficiency they are implemented using 32-bit registers. Using 64-bit values for random number generation generally requires multiplying two 64 bit values and storing 128-bit quantities with all the complications that entails.

Generating 64-bit random numbers uniformly, across the entire 64-bit range is simple. Generate two 32 bit numbers, shift one up by 32 bits, and ‘or’ them together:

```u64 getRandom64()
{
u64 low    = lcng.getRandom();
u64 high   = lcng.getRandom();
u64 random = low | (high << 32);
return random;
}
```

Generating 32-bit numbers in a range, that is given a ‘high’ and a ‘low’ number is straightforward in 32 bits, if you have access to a 64-bit register. The key is multiplying the result by the difference between high and low, and keeping just the bits above 32:

```u32 getRandomInRange( u32 low, u32 high )
{
u32 diff = low - high;
u64 v = lcng.getRandom();
v *= diff;
return (u32)(( v >> 32 ) + low );
}
```

Doing this for a range above 64 bits gets tricky because you’re back to needing to multiply by 2 64-bit registers.

The solution is simple. Implement a 64-bit multiply that keeps only the top 64 bits of the resulting 128-bit quantity:

```u64 getRandomInRange( u64 low, u64 high )
{
u64 diff = high - low;
if ( diff < U32_MAX )
return getRandomInRange( (u32)low, (u32)high );

u64 rlow  = lcng.getRandom();
u64 rhigh = lcng.getRandom();
u64 vlow  = diff & 0xFFFFFFFF;
u64 vhigh = diff >> 32;

u64 r  = (( rhigh * vlow ) >> 32 );
r += (( rlow * vhigh ) >> 32 );
r += ( rhigh * vhigh );
r += low;
return r;
}
```