CSC231 Factorial.asm

From dftwiki3
(Redirected from CSC220 Factorial.asm)
Jump to: navigation, search

--D. Thiebaut 15:24, 22 November 2010 (UTC)


factorial.asm

Python Version

  • A very simple python version:


def fact( n ):
    if n <= 1:
        return 1
    return n * fact( n-1 )

def main():
    N = input( "N? " )
    print "fact( %d ) = %d" % ( N, fact( N ) )



Assembly Version 1


This version passes n to the recursive function fact() in eax, and gets n! back also in eax.

;;; factorial.asm
;;; D. Thiebaut
;;; computes factorial of n
;;; requires driver.c, asm_io.o, and asm_io.inc
;;; 
;;; compile and link as follows:
;;;
;;;  nasm -f elf -F stabs factorial.asm
;;;  gcc -o factorial driver.c asm_io.o factorial.o
;;; 
%include "asm_io.inc"
        
%assign EXIT        1

        ;; -------------------------
        ;; data segment
        ;; -------------------------
        section .data
msg1    db      "factorial(",0
msg2    db      ") = ",0
i       dd      0

        ;; -------------------------
        ;; code area
        ;; -------------------------
        section .text
        global  asm_main

;;; ---------------------------------------------------------
;;; main program
;;; ---------------------------------------------------------
asm_main:       
;;; for i in range( 10 ):
        mov     dword[i],0
for:    cmp     dword[i],10
        jge     done

;;;     print "fact( %d ) = %d" % (i, fact(i) )
        
forBody:    
        mov     eax, dword[i]
        call    fact
        push    eax             ; save fact(i) in stack

        mov     eax, msg1        
        call    print_string    ; prints "fact( "

        mov     eax, dword[i]   ; get i
        call    print_int       ; print i

        mov     eax, msg2       ; print ") = "
        call    print_string
        
        pop     eax             ; get fact(i) back from stack
        call    print_int       ; print fact(i)

        call    print_nl        ; next line

        inc     dword[i]
        jmp     for
done:           

        ;; return to C program
        ret


;;; ---------------------------------------------------------
;;; fact:        computes the factorial of n passed in eax
;;;              and returns result in eax
;;; ---------------------------------------------------------
fact:   cmp     eax,1
        
        ;; test for stopping condition
        
        jg      recurse
        mov     eax,1
        ret

        ;; recursive step
        
recurse:
        push    eax             ; save n in eax
        dec     eax             ; n-1 in eax
        call    fact            ; recursive call, get fact(n-1) in eax
        pop     ebx             ; get n back, and save it in ebx
        mul     ebx             ; edx:eax <-- eax * ebx (we drop edx)
        ret


Assembly Version 2


This version passes n through the stack, and gets the result back in the stack.

;;; ; factorial.asm
;;; ; D. Thiebaut
;;; ; computes factorial of n
;;; ; requires driver.c, asm_io.o, and asm_io.inc
;;; ;
;;; ; compile and link as follows:
;;; ;
;;; ;  nasm -f elf -F stabs factorial.asm
;;; ;  ld -melf_i386 -o fact fact.o 231Lib.o
;;; ;
extern _printDec
extern _println        

EXIT            equ     1

;;;  -------------------------
;;;  data segment
;;;  -------------------------
                section .data
        msg1    db      "factorial(",0
        msg2    db      ") = ",0
        i       dd      0

;;;  -------------------------
;;;  code area
;;;  -------------------------
                section .text
                global  _start

;;; ; ---------------------------------------------------------
;;; ; main program
;;; ; ---------------------------------------------------------
_start: 
;;; ; for ( int i=0; i<10; i++ )
                mov     dword[i],0
for:            cmp     dword[i],10
                jge     endFor

;;; ;     print( fact(i) )

forBody:
                mov     eax, dword[i]
                push    eax     ; make room in stack for returned value
                push    eax     ; pass i
                call    fact
                pop     eax     ; get i!

                call    _printDec
                call    _println

                inc     dword[i]
                jmp     for
endFor:

;;;  return to OS
                mov     eax, EXIT
                mov     ebx, 0
                int     0x80


;;; ; ---------------------------------------------------------
;;; ; fact:        computes the factorial of n passed in the stack
;;; ;              return n! in the stack
;;; ;              +--------------+
;;; ;              |(place for n!)| ebp+12
;;; ;              +--------------+
;;; ;              |       n      | ebp+8
;;; ;              +--------------+
;;; ;              | ret addr. *  | ebp+4
;;; ;              +--------------+
;;; ;              |    old ebp   |<-- esp <-- ebp
;;; ;              +--------------+ 
;;; ; 
;;; ; ---------------------------------------------------------
fact:           push    ebp
                mov     ebp, esp
        
%define         n       dword[ebp+8]
%define         nfact   dword[ebp+12]
        
        
;;;  test for stopping condition

                cmp     n, 1    ; n==1 ?
                jg      .recurse
                mov     nfact,1 ; yes, then n! = 1
                pop     ebp     ; return to caller
                ret     4

;;;  recursive step

.recurse:
                push    eax     ; save regs used
                push    ebx
                push    edx
        
                mov     eax, n  
                dec     eax     ; n-1 in eax
                push    eax     ; make room for returned fact(n-1)
                push    eax     ; pass n-1
                call    fact    ; recursive call
                pop     ebx     ; get fact(n-1) in ebx
                mov     eax, n
                mul     ebx     ; edx:eax <-- n * (n-1)!
        
                mov     nfact, eax ; that's n!
                                ; drop edx
                pop     edx     ; restore regs
                pop     ebx
                pop     eax
        
                pop     ebp     ; return
                ret     4














A GUI Version in Python

  • This is an illustration of how human beings would "play" factorial


# Illustrated factorial in Python 3
# D. Thiebaut
students = [ "Alka", "Marie", "Alex", "Fiona", "Siri", "Alka" ]

def fact( n, level ):
    print( level*3*' ', students[level], "starting fact( %d )" % n )
    if n <= 1:
        print( level*3*' ', students[level], "n<=1 return 1" )
        return 1

    print( level*3*' ', students[level], "calling fact( %d )" % (n-1) )
    temp =  fact( n-1, level+1 )
    print( level*3*' ', students[level], "got result: temp = ", temp )
    print( level*3*' ', students[level], "returning %d*%d = %d" % (n, temp, n*temp) )
    return n * temp


def main():
    x = int( input( "N? " ) )
    print( "fact( %d ) = %d\n" % ( x, fact( x, 0 ) ) )


main()

Output

N? 5
 Alka starting fact( 5 )
 Alka calling fact( 4 )
    Marie starting fact( 4 )
    Marie calling fact( 3 )
       Alex starting fact( 3 )
       Alex calling fact( 2 )
          Fiona starting fact( 2 )
          Fiona calling fact( 1 )
             Siri starting fact( 1 )
             Siri n<=1 return 1
          Fiona got result: temp =  1
          Fiona returning 2*1 = 2
       Alex got result: temp =  2
       Alex returning 3*2 = 6
    Marie got result: temp =  6
    Marie returning 4*6 = 24
 Alka got result: temp =  24
 Alka returning 5*24 = 120
fact( 5 ) = 120