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

时间:2015-05-21 11:11:46

标签: algorithm assembly x86-16 factorial

我在一个旧网站上找到了这个代码(无法访问所有者),它计算用户输入的数字的阶乘(最多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

1 个答案:

答案 0 :(得分:1)

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

这里没有使用

bignum_add,它会使用类似的逻辑为乘法添加两个bignums。其余的只是做明显事情的助手。