I found this code on an old website (have no access to owner), It computes the factorial of a user entered number (up to 255) and it works fine. My problem is that I can figure out how the algorithm works, I do not understand it. I would appreciate it if someone would tell me how it works in human language.
data segment
b1 db 512 dup(0)
b2 db 512 dup(0)
msg db 0dh,0ah,"Number:$"
fac db 0dh,0ah,"Factorial",0dh,0ah,"$"
data ends
bignum_get macro var
local exit,get,loo,skip
xor cx,cx
lea si,var
mov di,si
mov ah,01h
get:
int 21h
cmp al,0dh
je exit
sub al,30h
mov [si],al
inc si
inc cx
jmp get
exit:
shr cx,1
jz skip
dec si
loo:
mov ah,[si]
mov al,[di]
mov [si],al
mov [di],ah
dec si
inc di
loop loo
skip:
endm
geti macro
local exit,get
xor bx,bx
mov dx,bx
mov cx,00ah
get:
push bx
;Read character
mov ah,01h
int 21h
xor ah,ah
pop bx
;If enter stop
cmp al,0dh
jz exit
sub al,30h
;Multply By 10
push ax
mov ax,bx
mul cx
mov bx,ax
pop ax
;add
add bx,ax
;redo
jmp get
exit:
mov ax,bx
endm
bignum_put macro var
local put,en,nxt,exit
lea si,var
mov di,si
mov cx,0200h
add di,cx
dec di
en:
cmp BYTE PTR [di],00h
jne nxt
dec di
jmp en
nxt:
mov ah,02h
put:
mov dl,[di]
add dl,30h
int 21h
cmp si,di
je exit
dec di
loop put
exit:
endm
bignum_add macro b1,b2
local ader,exit
lea si,b1
lea di,b2
mov cx,0200h
mov bl,10
ader:
mov al,[di]
mov ah,[si]
add al,ah
jz exit
xor ah,ah
div bl
mov [si],ah
inc si
add [si],al
inc di
loop ader
exit:
endm
bignum_mul macro b1
local loo,exit
cmp dl,01h
jz exit
lea si,b1
mov dh,10
xor bx,bx
mov cx,0200h
loo:
mov al,[si]
xor ah,ah
mul dl
add ax,bx
div dh
mov [si],ah
inc si
mov bl,al
loop loo
exit:
endm
puts macro msg
push ax
push dx
mov dx,offset msg
mov ah,09h
int 21h
pop dx
pop ax
endm
assume cs:code,ds:data
code segment
start:
mov ax,data
mov ds,ax
lea si,b1
mov BYTE PTR [si],01h
puts msg
geti
mov dl,al
loo:
push dx
bignum_mul b1
pop dx
dec dl
jnz loo
puts fac
bignum_put b1
mov ah,4ch
int 21h
code ends
end start
Which part is unclear?
First it reads an integer using geti
which utilizes the well known x = 10*x + c - '0'
formula to convert string to number.
Then it initializes the bignum accumulator to 1
and multiplies it by the input number using bignum_mul
in a loop, counting down to 1
, calculating 1*x*(x-1)*(x-2)*...*1
. bignum_mul
itself multiplies each digit by the given integer, then splits it into two through dividing by 10 so it gets the correct digit as the remainder and the carry as the quotient. The latter is moved into bx
and added in the next iteration.
bignum_add
is not used here, it would add two bignums using similar logic to the multiplication. The rest are just helpers doing obvious things.