I'm supposed to write program in NASM (and test it under DosBox) that would calculate factorial with one constraint: result will be stored in upto 128bits. Therefore maximum to be calculated is factorial(34). My problem is that I have no idea how to print such a big number. The only hint I have is to use DOS interrupts but after a long research I've found nothing that would help me.
The part calculating factorial that I've already made is:
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's 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's 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
And well... I know how to print 32 bits number but it's probably not the way I would like to print 128b number:
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
Could anyone help me and give some hints how to deal with it? I don't even know whether factorial is calculated properly because I can't print anything bigger than 32b...
You do it the precisely same way as you handle the small number, that is successively divide by ten and get the smallest digit as remainder. Don't forget to reverse the order of the digits when printing though (the stack comes in handy for this.)
A multi-word division by ten is easily implemented by walking through the words in the extended integer from most to least significant, dividing by ten, and carrying the intermediate remainders to the next division as the upper word (in DX, where DIV divides DX:AX.)
For reference here is the equivalent algorithm in C which you may use as a starting point. Where the 128-bit number is stored as eight little-endian 16-bit words.
For extra credit you might use the x86's BCD instructions (AAM in this case) as an alternative and calculate multiplications of the factorial directly in decimal format.
First of all be sure to get yourself a usable debugger if you haven't already, so you may step through the test cases and follow along on paper. Personally I used Turbo Debugger back in the day and I believe NASM is capable of producing compatible symbolic information. I don't mean to nag but previous posters concerned with 16-bit DOS assembly have tended to omit this crucial step of the process.