I want to generate uniform integers that satisfy 0 <= result <= maxValue
.
I already have a generator that returns uniform values in the full range of the built in unsigned integer types. Let's call the methods for this byte Byte()
, ushort UInt16()
, uint UInt32()
and ulong UInt64()
. Assume that the result of these methods is perfectly uniform.
The signature of the methods I want are uint UniformUInt(uint maxValue)
and ulong UniformUInt(ulong maxValue)
.
What I'm looking for:
- Correctness
I'd prefer the return values to be distributed in the given interval.
But a very small bias is acceptable if it increases performance significantly. By that I mean a bias of an order that allows distinguisher with probability 2/3 given 2^64 values.
It must work correctly for anymaxValue
. - Performance
The method should be fast. - Efficiency
The method does consume little raw randomness, since depending on the underlying generator, generating the raw bytes might be costly. Wasting a few bits is fine, but consuming say 128 bits to generate a single number is probably excessive.
It's also possible to cache some left over randomness from the previous call in some member variables.
Be careful with int overflows, and wrapping behavior.
I already have a solution(I'll post it as an answer), but it's a bit ugly for my tastes. So I'd like to get ideas for better solutions.
Suggestions on how to unit test with large maxValue
s would be nice too, since I can't generate a histogram with 2^64 buckets and 2^74 random values. Another complication is that with certain bugs, only some maxValue
distributions are biased a lot, and others only very slightly.
floor(maxValue/maxfordatatype*existingrandom())
? – Ergocalciferolmaxfordatatype
is significantly larger thanmaxValue
, in which case it'd have efficiency issues. – Roscoeroscommon1/maxValue
, a bias of the same magnitude means that some fields might not be reached at all, and others twice as often as they should.System.Random
uses a similar algorithm inNext(maxValue)
, and I can distinguish it from true random numbers using only a few samples. – Roscoeroscommon