The algorithm works like the original but without any floating point operations.
There are faster RNG's of course, but this one produces exactly the same output.
Code: Select all
RND:
ld hl (SEED) // fetch Speccy's 16-bit seed
inc hl // SEED+1
ld a h
or l
jr z L2 // special case: SEED+1 = 65536 handled at L2
xor a
ld c a
ld d h
ld e l
add hl hl
rla
add hl hl
rla
add hl hl
rla
add hl de
adc c
add hl hl
rla
add hl hl
rla
add hl de
adc c
add hl hl
rla
add hl de
adc c // 22-bit number in a,hl = (SEED+1) * 75
ld d c
ld e a
sbc hl de // calculate the remainder of (SEED+1) * 75 modulo 65537
jr c 1
dec hl // remainder-1
L1:
ld (SEED) hl // done, set (remainder-1) as new seed
// cost: 239 T up to here
// to obtain a 16-bit random number, uncomment the line below
//ret
// This part is building a float between 0 and 1 (exclusive) on the calculator stack:
call StackHLAsFlt // put (remainder-1) on calculator stack
ld a (hl) // the exponent of the float
and a
ret z // (remainder-1) is 0 -> done
sub 16 // exponent-16 is like division by 65536
ld (hl) a // ...so (remainder-1)/65536 is the RND result
ret
L2:
ld hl 65461 // for special case (SEED+1)=65536 set the known result
jr L1
StackHLAsFlt:
push hl
ld bc 5
call $1F05 // 5 bytes to calculator stack
ex de hl
ld (STKEND) hl
dec hl
dec hl
pop de // de=value to stack
ld c b // c=sign of value (0=positive)
call $329E // stack c,de as float (or as 0 if de=0)
// above call does 1 extra-pop -> returns directly to caller of this routine
Certainly there's been something like that posted before, but the search didn't turn it up.