-
-
Notifications
You must be signed in to change notification settings - Fork 65
Description
We provide two random number generation functions:
uint32_t random(void); // [0, 2^32)
int rand(void); // [0, 2^23)
Currently rand() wraps random(). To do this, it just needs to clear bit 23 to make sure the result is [0, RAND_MAX] or [0, 2^23). I believe the intended implementation is return (random() & 0x7FFFFF), however, since the sbc instruction is used in a place where carry is unknown, the result may or may not be off by one (Although it will still be [0, RAND_MAX]).
_rand:
; the last operation performed by _random is add hl, de \ adc a, c \ ld e, a \ ret
; therefore the state of carry is indeterminate
call _random
ld de, 8388608
sbc hl, de ; carry is unknown here
ret p
add hl, de
retWe can fix it so rand() always does return (random() & 0x7FFFFF) by doing this:
_rand:
call _random
ld de, 8388608
add hl, de
ret c
add hl, de
retPros:
rand()andrandom()produce consistent results- 1 byte smaller
Cons:
rand()will output different results when recompiling a program. More specifically, 50% of the results fromrand()will be one higher than they were before.
Here is how the test cases (#760) differ for rand with this change. rand_X calls srand every iteration, and since the initial state is 1,2,3,4,5,... carry will almost never be set. But rand_0 does call rand several times, allowing the state to become more randomized and start emitting carrys
