Нахождение факториала большого числа в сборке не работает при n> = 15 - PullRequest
0 голосов
/ 30 апреля 2020

Я использую MASM и dosbox для этого, в основном конвертирую версию C в сборку.

int main()
{
    int a[20001];
    int temp,digit,n,i,j=0;
    scanf("%d",&n);
    a[0]=1;
    digit=1;
    for(i=2;i<=n;i++)
    {
        int num=0;
        for(j=0;j<digit;j++) 
        {
            temp=a[j]*i+num;
            a[j]=temp%10;
            num=temp/10;
        }
        while(num)
        {
            a[digit]=num%10;
            num=num/10;
            digit++;
        }
    }
    for(i=digit-1;i>=0;i--)
        printf("%d",a[i]);
    printf("\n");
    return 0;

Я думаю, что не может быть проблем с переполнением регистров, если я буду следовать по этому маршруту , Хорошо работает с 1! до 14 !, но застревает при вычислении 15!.

enter image description here

Вот код

  .MODEL SMALL,STDCALL
  .386


  .DATA
  digit db 0
  n     db ?
  i     db 0
  j     db 0
  num   db 0
  array db 10000 dup(0)



  .CODE
  main proc
    mov ax,@data
    mov ds,ax

;-----------------load input to n
    mov  bx, 0
    Newchar:
      mov  ah, 1
      int  21h 
      sub  al, 30h 
      jl  endinput
      cmp  al, 9    
      jg  endinput
      cbw  
      xchg   ax, bx
      mul   cx
      xchg  ax, bx    
      add   bx, ax 
      jmp   newchar 
    endinput:
    mov n,bl
;-----------------


    mov al,1
    mov array[0],al

    mov al,1
    mov digit,al

    mov ch,0
    mov cl,n
    sub cl,2
    firstloop:
      ;i = n - cx = al
      mov ah,0
      mov al,n
      sub ax,cx
      mov i,al
      ;num = 0 = dl
      mov dh,0
      mov dl,0
      mov num,dl

      ; j = 0 = bx
      mov bx,0
      secondloop:
        ; temp=a[j]*i+num;
        mov al,i
        mov ah,array[bx]
        mul ah;->ax
        add ax,dx
        mov dh,10;borrow bh, then turn it back to 0
        div dh
        ; a[j]=temp%10;
        mov array[bx],ah
        ; num=temp/10;
        mov dl,al
        mov num,dl
        mov dh,0

        add bx,1
        mov j,bl
        cmp bl,digit
        jl secondloop

      whileloop:
        mov dl,num
        mov dh,0
        cmp dx,0
        je tonext
        mov ax,dx
        mov dh,10;borrow bh, then turn it back to 0
        div dh
        mov dh,0
        mov j,bl
        mov bh,0;bx was j, turn it to digit
        mov bl,digit
        mov array[bx],ah
        ; num=num/10;
        mov dl,al
        ; digit++;
        add bl,1
        mov digit,bl
        mov bl,j;turn bx back to j

        cmp dx,0
        jne whileloop

      tonext:
        mov al,i
        add al,1
        mov i,al
        sub cx,1
        cmp al,n
        jle firstloop




      ; reversely print the array
      mov bh,0
      mov bl,digit
      sub bl,1

    printloop:
      MOV  DL,array[bx]
      add dl,30h
      mov ah,2
      int 21h
      sub bx,1
      cmp bx,0
      jnl printloop

      jmp exit;

    exit:
      mov ah,4ch
      int 21h
    main endp
    end main

Я думаю, что алгоритм в версии C может избежать общей проблемы переполнения регистра. Так что я не знаю, где улучшить мой код. У меня есть два предположения:

  1. Там что-то еще переполнено. Но я не могу его найти.
  2. Есть некоторые неизвестные ограничения с dosbox

Код ооочень длинный, я буду очень признателен, если кто-нибудь может дать мне какой-нибудь совет.

...