First; understand that (for random number generation) modulo by a "non-power of 2" causes bias and should be avoided. For example, if you want a number from 0 to 2 and start with a 4-bit random number (values 0, 1, 2, .., 14, 15) then after the "modulo 3" the values will become 0, 0, 0, 1, 1, 1, ..., 4, 4, 4, 5) and the value 5 will be a lot less likely than any other value.
The easiest way to fix "bias caused by modulo of non-power of 2" is to mask (with AND) to the next highest power of 2 minus 1, then discard the number and retry if the value is still out of range. For example, if you want a number from 0 to 2 and start with a 32-bit random number; you'd do "number = number & (4-1)" (because 4 is the next highest power of 2), and then if the number is larger than 2 you'd discard it and get a whole new random number again.
Now...
If you're retrying to avoid "bias caused by modulo of non-power of 2"; why not also retry if the number happens to be an even number in the range 162 to 278?
For example (in C):
#define MAX_VALUE 500
#define NEXT_POWER_OF_2 512
int getNumber(void) {
int number;
do {
number = rand();
number = number & (NEXT_POWER_OF_2 - 1);
} while( (number > MAX_VALUE) || ((number >= 162) && (number <= 278) && (number & 1 == 0)) );
}
For assembly:
;Input
; none
;
;Output
; eax = random number in range from 0 to MAX_NUMBER that is not an even number from 168 to 278
%define MAX_VALUE 500
%define NEXT_POWER_OF_2 512
getNumber:
call getRandomDword ;eax = random 32-bit value
and eax,NEXT_POWER_OF_2-1 ;eax = random N-bit value
cmp eax,MAX_VALUE ;Is it too large?
ja getNumber ; yes, retry
cmp eax,278 ;Is it larger than the "not even" range?
ja .done ; yes, allow the number
cmp eax,162 ;Is it smaller than the "not even" range?
jb .done ; yes, allow the number
test al,1 ;Is it even?
je getNumber ; yes, retry
.done:
ret
Note: I have no idea if you want 16-bit, 32-bit or 64-bit code, or if the code has to work on which CPUs, or what the source of randomness will be. For example, recent CPUs support a rdrand
instruction that is relatively slow (it's intended for cryptography not speed but can be used to regularly "re-seed" a pseudo-random number generator) but if you need to make sure the code works fine on an old 80386 then...