这段代码的算法是如何工作的?

How does the algorithm of this code work?

我在一个旧网站上找到了这段代码(无法访问所有者),它计算用户输入数字的阶乘(最多 255)并且工作正常。我的问题是我可以弄清楚算法是如何工作的,我不明白。如果有人能用人类语言告诉我它是如何工作的,我将不胜感激。

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

哪一部分不清楚? 首先,它使用 geti 读取一个整数,该整数利用众所周知的 x = 10*x + c - '0' 公式将字符串转换为数字。 然后它将 bignum 累加器初始化为 1 并在循环中使用 bignum_mul 将其乘以输入数字,倒数到 1,计算 1*x*(x-1)*(x-2)*...*1bignum_mul 本身将每个数字乘以给定的整数,然后通过除以 10 将其分成两部分,从而得到正确的数字作为余数,进位作为商。后者移入 bx 并在下一次迭代中添加。

bignum_add 在这里没有使用,它会使用与乘法类似的逻辑添加两个 bignums。其余的只是帮手做一些显而易见的事情。