Reputation:
I'm learning assembly, and I found this code:
; Initialized seed value
xor [myseed], esp
; Generate random string
call randletter
mov [message], al ; Write 1st letter
; myrand gives a pseudo-random number in range 0..max
; inputs:
; edi - max value
; outputs:
; eax - generated value
myrand: mov eax, [myseed] ; Load state of generator
mov ecx, 4000000001
mul ecx ; Multiply state var by a constant
add eax, 3333333333 ; Add another constant
mov [myseed], eax ; And save the result
xor edx, edx
inc edi
div edi ; Divide state var in edx:eax by (max+1) in edi
mov eax, edx ; div instruction writes remainder into edx, so copy to eax
ret
; randletter gives a random lowercase letter
; inputs: no
; outputs:
; al - random lowercase letter (ASCII code)
randletter:
mov edi, 25
call myrand
add al, 'a'
ret
section .data
myseed: dd 123456789
Now I know that, this is linear congruential generator in the method myrand
.
My question is how the number from myrand
can cause the number from 97 to 122 in ASCII in randletter
? And why they have add al, a
in myrand
. How can that help?
Upvotes: 1
Views: 928
Reputation: 39176
The ASCII codes for the lowercase letters vary from 97 for 'a' to 122 for 'z'.
The output from myrand
(25) is from 0 to 25.
randletter:
mov edi, 25
call myrand ; -> EAX == [0,25]
add al, 'a' ; -> AL == [0,25] + 97 == [97,122] == ['a','z']
ret
No matter the value in myseed, the division div edi
will, given that EDI=25+1
, always produce a remainder from 0 to 25. This remainder becomes the result of the myrand function.
EDI=25
...
mov [myseed], eax ; And save the result
xor edx, edx ; EDX=0
inc edi ; -> EDI == 25 + 1 == 26
div edi ; Divide EDX:EAX by 26 -> remainder EDX == [0,25]
mov eax, edx ; return result in EAX
ret
The calculation that leads to the new value of myseed is only important for the quality of the distribution of the random numbers.
The restriction of the output range is exclusively obtained from taking the remainder of the division.
Upvotes: 2