    .MODEL  SMALL
    .DATA      
    BIT     EQU 20              ; 答案的最大位长
    ANS     DB  64 DUP(0)       ; 存放高精度答案
    N       DB  19              ; N 为待计算阶乘的对象
    TEN     DB  10              ; 存放10进制的基数

    .CODE
    .STARTUP
    mov     dl, 0
INPUT:
    mov     ah, 1
    int     21h
    sub     al, 30h
    js      FINISH_INPUT
    push    ax
    mov     al, dl
    mov     dl, 10
    mul     dl
    mov     dl, al
    pop     ax
    add     dl, al
    jmp     INPUT

FINISH_INPUT:
    mov     N, dl
    mov     dl, 10
    mov     ah, 2
    int     21h
    mov     dl, 13
    mov     ah, 2
    int     21h
    MOV     CL, N               ; CL 存放当前乘数
    MOV     ANS, 1              ; 初始化答案的个位为 1
FOR:                            ; 依次处理各个乘数
    CMP     CX, 2
    JS      PRINT               ; 乘数为 1 时停止
    JMP     WORK                ; 否则将该乘数乘进答案数组
RTN:
    DEC     CX                  ; 乘数减 1
    JMP     FOR                 ; 重复以上步骤
    
WORK:          
    MOV     BX, 0               ; BX 跟踪答案数组的偏移量 
TIMES:                          ; 将乘数乘到答案的各个位上
    CMP     BX, BIT             
    JZ      FINISH_TIMES        ; 已乘完各个位，准备进位
    MOV     AL, CL              
    MUL     BYTE PTR ANS[BX]    ; 乘法操作，积在 AL 中
    MOV     ANS[BX], AL         ; 将积存入答案数组的对应位
    INC     BX                  ; 更新偏移量
    JMP     TIMES               ; 继续对剩余的位执行乘法操作
FINISH_TIMES:
    MOV     BX, 0               ; BX 跟踪答案数组的偏移量
CARRY:                          ; 对答案数组执行进位操作
    CMP     BX, BIT
    JZ      RTN                 ; 已完成所有进位，可以返回
    MOV     AX, 0
    MOV     AL, ANS[BX]
    DIV     BYTE PTR TEN       ; 对 10 取余数和商
    MOV     ANS[BX], AH         ; 余数重新放进该位
    ADD     ANS[BX+1], AL       ; 商作为进位累加到下一位
    INC     BX                  ; 更新偏移量
    JMP     CARRY               ; 继续对剩余的位执行进位操作
PRINT:                          ; 打印高精度答案
    MOV     BX, BIT             ; BX 跟踪答案数组的偏移量
    MOV     CL, 0               ; CL 为标识位（为1时0需要输出）
PRINT_DIGIT:                    ; 打印一个数位
    MOV     DL, ANS[BX]         ; DL 为当前待输出的数位
    CMP     DL, 0
    JZ      SKIP_SET            ; DL 不为 0，才设置标志位
    MOV     CL, 1               ; 表明之后的 0 不再是前导 0
SKIP_SET:
    CMP     CL, 0               
    JZ      SKIP_PRINT          ; 还未遇见非 0 的数，不可输出
    ADD     DL, 48
    MOV     AH, 2
    INT     21H                 ; 输出当前数位的值
SKIP_PRINT:
    CMP     BX, 0               
    JZ      FINISH              ; 已打印完所有数位，程序结束
    DEC     BX                  ; 更新偏移量
    JMP     PRINT_DIGIT         ; 继续打印剩余数位

FINISH:
    .EXIT
    END

    
