ASM печатает большие номера

Я должен написать программу в NASM (и протестировать ее под DosBox), которая будет вычислять factorial с одним ограничением: результат будет храниться до 128 бит. Поэтому максимум для расчета является факториальным (34). Моя проблема в том, что я понятия не имею, как печатать такое большое число. Единственный намек, который у меня есть, - использовать прерывания DOS, но после долгого исследования я не нашел ничего, что могло бы помочь мне.

Фрагмент, который я уже сделал, вычисляет:

        org 100h
section     .text
factorial   dw 1200h

        xor edx, edx
        xor eax, eax
        mov ax, 6d      ;we'll be calculating 6!
        mov word [factorial+16], 1d     ;current result is 1

wloop:
        mov cx, 08h     ;set loop iterator to 8
        xor edx, edx    ;clear edx
    mloop:                  ;iterate over cx (shift)
        mov bx, cx      ;copy loop iterator to bx (indirect adressing will be used)
        add bx, bx      ;bx*=2
        push ax         ;store ax (number to multiply by)
        mul word[factorial+bx]  ;multiply ax and result
        mov word[factorial+bx], ax  ;store new result in [factorial+2*cx]
        pop ax          ;restore previous ax
        push dx         ;transfer from mul is stored in stack
        loop mloop      ;loop over cx until it 0

        mov cx, 7h      ;set loop iterator to 7
    tloop:                  ;iterate over cx, adding transfers to result
        pop dx          ;pop it from stack
        mov bx, cx      ;bx = cx
        add bx, bx      ;bx = bx+bx
        adc [factorial+bx],dx ;add transfer to [factorial+2*cx]
        loop tloop      ;loop over cx until it 0

        pop bx          ;one redundant transfer is removed from stack
        dec ax          ;decrease ax (number to multiply by)
        cmp ax, 0       ;if ax is non-zero...
        jne wloop       ;...continue multiplying

        movzx eax, word[factorial+16] ;load last 32 bits of result...
        call println    ;...and print them

        jmp exit        ;exit program

И хорошо... Я знаю, как печатать 32-битное число, но это, вероятно, не так, как хотелось бы напечатать номер 128b:

println:                    ;Prints from eax
        push eax
        push edx
        mov ecx, 10
    loopr:  
        xor edx, edx
        div ecx         ; eax <- eax/10, edx <- eax % 10
        push eax        ; stack <- eax (store, because DOS will need it)
        add dl, '0'     ; edx to ASCII
        mov ah,2        ; DOS char print
        int 21h         ; interrupt to DOS
        pop eax         ; stack -> eax (restoring)
        cmp eax, 0
        jnz loopr

        mov dl, 13d     ;Carriage Return
        mov ah, 2h
        int 21h
        mov dl, 10d     ;Line Feed
        mov ah, 2h
        int 21h

        pop edx
        pop eax
        ret

Может ли кто-нибудь помочь мне и дать некоторые подсказки, как с этим бороться? Я даже не знаю, правильно ли вычисляется факториал, потому что я не могу напечатать что-либо большее, чем 32b...

3
18 дек. '13 в 16:16
источник поделиться
1 ответ

Вы делаете это точно так же, как вы обрабатываете небольшое число, которое последовательно делит на десять и получает наименьшую цифру в качестве остатка. Не забудьте изменить порядок цифр при печати (для этого удобна стека).

Деление на несколько слов на десять легко реализуется путем прохода слов в расширенном целом от большинства до наименее значимых, деления на десять и переноса промежуточных остатков в следующее деление как верхнее слово (в DX, где DIV делит DX: AX.)

Для справки здесь приведен эквивалентный алгоритм в C, который вы можете использовать в качестве отправной точки. Если 128-разрядное число хранится в виде восьми младших 16-разрядных слов.

uint16_t extended_div(uint16_t *num, uint16_t den, size_t len) {
    ldiv_t acc = { 0 };
    num += len;
    do {
        acc = ldiv(acc.rem << 16 | *--num, den);
        *num = acc.quot;
    } while(--len);
    return acc.rem;
}

Для дополнительного кредита вы можете использовать инструкции x86 BCD (AAM в этом случае) в качестве альтернативы и рассчитать умножения факториала непосредственно в десятичном формате.


Прежде всего, убедитесь, что у вас есть полезный отладчик, если вы еще этого не сделали, поэтому вы можете пройти тестовые примеры и следовать на бумаге. Лично я использовал Turbo Debugger еще в тот же день, и я считаю, что NASM способен создавать совместимую символическую информацию. Я не хочу петь, но предыдущие плакаты, связанные с 16-разрядной сборкой DOS, как правило, не учитывают этот важный шаг процесса.

6
18 дек. '13 в 16:27
источник

Посмотрите другие вопросы по меткам или Задайте вопрос