I need a function to generate random integers. (assume Java long
type for now, but this will be extended to BigInteger
or BitSet
later.)
The tricky part is there is a parameter P that specifies the (independent) probability of any bit in the result being 1.
If P = 0.5 then we can just use the standard random number generator. Some other values of P are also easy to implement. Here's an incomplete example:
Random random = new Random();
// ...
long nextLong(float p) {
if (p == 0.0f) return 0L;
else if (p == 1.0f) return -1L;
else if (p == 0.5f) return random.nextLong();
else if (p == 0.25f) return nextLong(0.5f) & nextLong(0.5f);
else if (p == 0.75f) return nextLong(0.5f) | nextLong(0.5f);
else if (p == 0.375f) return nextLong(0.5f) & nextLong(0.75f); // etc
else {
// What goes here??
String message = String.format("P=%f not implemented yet!", p);
throw new IllegalArgumentException(message);
}
}
Is there a way to generalise this for any value of P between 0.0 and 1.0?
Here's how I solved it in the end.
This was partly inspired by Ondra Žižka's answer.
The benefit is that it reduces the number of calls to
Random.nextLong()
to 8 calls per 64 bits of output. For comparison, rolling for each individual bit would require 64 calls. Bitwise AND/OR uses between 2 and 32 calls depending on the value ofP
Of course calculating binomial probabilities is just as expensive, so those go in another lookup table.
It's a lot of code, but it's paying off in terms of performance.
Update - merged this with the bitwise AND/OR solution. It now uses that method if it guesses it will be more efficient (in terms of calls to
Random.next()
.)