Nonrecursive Factorial & Factorial Comparison

VSBrown 0 Tallied Votes 609 Views Share

A program that will test the Nonrecursive Factorial procedure using a value passed in by the program user and will also do a time comparision of the Nonrecursive and Recursive Factorial functions.

TITLE: NonrecursiveFactorial&FactorialComparison (Factorials.asm)

;------------------------------------------------------------
; Name: 
;
; Filename: Factorials.asm
;
; Project #: 6
;
; Completed: March 15, 2003
;
; Description: My sixth assembly program. A program that will
;              test the Nonrecursive Factorial procedure using
;              a value passed in by the program user and will
;              also do a time comparision of the Nonrecursive
;              and Recursive Factorial functions.
;              From Assembly Language For Intel-Based Computers,
;              4th Ed. by Kip R. Irvine. 
;              (Problem #3 and #4 on pg. 298)
;
; Reference:   Assembly Language For Intel-Based Computers,
;              4th Ed. by Kip R. Irvine
;              (Section 8.5.2 Calculating a Factorial)
;              (Fact.asm)
;------------------------------------------------------------
INCLUDE Irvine32.inc

.data
startTime dword 0
savedNum  sdword ?
numOfTimes = 00000FFFh;(squared) to calculate the factorial
caseTable byte '1'                ;lookup value
          dword enterInt          ;address of lookup value
entrySize = ($ - caseTable )
          byte '2'
          dword factCompare
          byte '3'
          dword endTest
          numberOfEntries = 3
msgIntro  byte "This is Your Name's sixth assembly program. A program that will",0dh,0ah
          byte "test the Nonrecursive Factorial procedure using a value passed in",0dh,0ah
          byte "by the program user and will also do a time comparision of the ",0dh,0ah
          byte "Nonrecursive and Recursive Factorial functions.",0dh,0ah,0
msgSelMn  byte " -----------------------------------------",0dh,0ah
          byte "|                 MENU:                   |",0dh,0ah
          byte "| 1. NonRecursive Factorial (Exercise #3) |",0dh,0ah
          byte "| 2. Factorial Comparison   (Exercise #4) |",0dh,0ah
          byte "| 3. Exit Program                         |",0dh,0ah
          byte " -----------------------------------------",0dh,0ah
          byte "Enter Selection: ",0
msgInputN byte "Enter the value of n to calculate. "
	  byte "( n must be <= 12 ) : ",0
msgFact   byte "Factorial =  ",0
msgError  byte "Sorry cannot calculate the following factorial because "
          byte "it is greater than 12! ",0dh,0ah
          byte "                                12 < ",0
msgNonRec byte "The time to do the Nonrecursive factorial = ",0
msgRec    byte "The time to do the Recursive factorial = ",0
msgEnd    byte "End Program",0dh,0ah,0

.code
main PROC
;///////Intro Message/////////////////////////////////
	mov edx,OFFSET msgIntro  ;intro message into edx
        call WriteString         ;display msgIntro
        call Crlf                ;endl
        call WaitMsg             ;pause message
        call Clrscr              ;clear screen
        call Menu                ;menu procedure

ExitProg::exit                   ;global label to exit
main ENDP

;------------------------------------------------
Menu PROC
;
; Receives: Nothing
; Returns: Nothing
;------------------------------------------------
	mov  edx,OFFSET msgSelMn ;ask user for input
	call WriteString         ;display msgSelMn
	call ReadChar		 ;read one character
	call Clrscr
        mov  ebx,OFFSET caseTable;point EBX to the table
	mov  ecx,numberOfEntries ;loop counter

        L1:
	cmp  al,[ebx]		 ;match found?
	jne  L2		         ;no: continue
	call NEAR PTR [ebx + 1]	 ;yes: call the procedure
	call WriteString	 ;display message
	call Crlf                ;endl
	call Clrscr              ;clear screen
	jmp  L3		         ;exit the search

        L2:
	add  ebx,5		 ;point to the next entry
	loop L1		         ;repeat until ECX = 0

        L3:
	jmp Menu	         ;run Menu again

Menu ENDP

;------------------------------------------------
enterInt PROC
;
; User input of n
; Receives: EAX = n
; Returns: EAX = n
;------------------------------------------------
    	mov edx, OFFSET msgInputN ;ask user to input n
    	call WriteString
    	call ReadInt	          ;int input by user
    	mov savedNum,eax
    	call Crlf
    	cmp eax, 0	          ;is n less than 0
    	jl endTest

    	mov edx, OFFSET msgFact
    	call WriteString
    	call nonRecurFact	  ;EAX = factorial(n)
    	call WriteDec	          ;display factorial
    	call Crlf
    	call Crlf
    	call WaitMsg
    	ret

enterInt ENDP

;-------------------------------------------------------
Factorial PROC
;
; Calculates a factorial
; Receives: [ebp+8] = n, the number to calculate
; Returns: EAX = factorial of n
;--------------------------------------------------------
;(Fact.asm)
	push ebp	         ;save stack base pointer
	mov  ebp, esp
	mov  eax, [ebp+8]	 ;get n
	cmp  eax, 0	         ;is n < 0?
	ja   L1	                 ;yes: continue
	mov  eax, 1	         ;no: return 1
	jmp  L2

        L1:
        dec  eax
	push eax	         ;Factorial(n-1)
	call Factorial

;Instructions from this point on execute when each
;recursive call returns.

        ReturnFact:
	mov  ebx, [ebp+8]	 ;get n
	mul  ebx	         ;edx:eax = eax * ebx

        L2:
        pop  ebp	         ;return EAX
	ret  4	                 ;clean up stack

Factorial ENDP

;------------------------------------------------
nonRecurFact PROC USES ECX EDX
;
; Calculates Nonrecursive Factorial
; Receives: EAX = n (as input by user)
; Returns: EAX = nonrecursive factorial
;------------------------------------------------
	.IF eax == 0 || eax == 1  ;special cases
	  mov eax, 1	          ;factorial == 1
	  jmp L2         	  ;quit procedure
	.ELSEIF eax > 12	  ;n is too large
	  mov edx, OFFSET msgError
	  call Crlf
	  call WriteString
	  jmp L2	          ;quit procedure
	.ENDIF

	mov ecx, eax	          ;ecx = counter

        L1:
	dec ecx	                  ;ecx = n - 1
	mul ecx	                  ;eax = n * (n - 1)

	cmp ecx, 1	          ;is counter > 1?
	ja L1	                  ;true? then continue

	L2:
	ret

nonRecurFact ENDP

;------------------------------------------------
factCompare PROC
;
; Receives: Nothing
; Returns: Nothing
;------------------------------------------------
        call enterInt
        mov ecx, numOfTimes	 ;counter
	call GetMseconds	 ;get miliseconds since midnight
	mov startTime, eax	 ;save start time

        L1:
	push ecx	         ;save outer loop counter
	mov ecx, numOfTimes	 ;counter inner loop

	L2:
	mov eax, savedNum
	call nonRecurFact        ;nonRecursive factorial
	loop L2	                 ;next inner loop iteration

	pop ecx	                 ;restore outer loop
	loop L1	                 ;inner loop

	call GetMseconds	 ;get miliseconds since midnight
	sub eax, startTime	 ;get running time
	mov edx, OFFSET msgNonRec
	call WriteString
	call WriteDec	         ;display time
	call Crlf

	mov ecx, numOfTimes	 ;counter
	call GetMseconds	 ;get miliseconds since midnight
	mov startTime, eax	 ;save starting time
        L3:
	push ecx	         ;save outer loop counter
	mov ecx, numOfTimes	 ;counter inner loop

	L4:
	push savedNum
	call Factorial	         ;recursive factorial
	loop L4	                 ;inner loop

	pop ecx	                 ;restore outer loop counter
	loop L3

	call GetMseconds	 ;get miliseconds since midnight
	sub eax, startTime	 ;get running time
	mov edx, OFFSET msgRec
	call WriteString
	call WriteDec	         ;display time
	call Crlf
	call Crlf
	call WaitMsg
	ret

factCompare ENDP

;------------------------------------------------
endTest PROC
;
; Receives: Nothing
; Returns: EDX = offset of message
;          Sets CF = 1 to signal end of program
;------------------------------------------------
        mov  edx,OFFSET msgEnd   ;msgEnd into edx
	call WriteString	 ;display message
	call Crlf                ;endl
	stc	                 ;CF = 1
	jc ExitProg    	         ;if CF=1 then jump to Global ExitProg

endTest ENDP

END main

Dani AI

Generated

— good foundation here. The program implements both recursive and nonrecursive factorials and a timing harness, but a few targeted fixes will prevent subtle bugs and make the timing results more reliable.

The recursive routine should preserve callee-saved registers and use a clearer base-case test. As written the proc uses EBX without saving it, and the compare/jump against 0 uses an unsigned jump that mismatches the comment and forces an extra recursion for n==1. A minimal, safe fix is to push/pop EBX and test explicitly for n <= 1:

push ebp
mov  ebp,esp
push ebx            ; preserve EBX

mov  eax,[ebp+8]    ; n
cmp  eax,1
jle  BaseCase
dec  eax
push eax
call Factorial
mov  ebx,[ebp+8]
mul  ebx

BaseCase:
mov  eax,1

pop  ebx            ; restore EBX
pop  ebp
ret  4

The timing harness also needs small robustness work. GetMseconds returns milliseconds since midnight, so a test that crosses midnight will underflow; add a wrap check (if end < start then add 86,400,000) before subtracting. For finer benchmarking on modern systems, prefer QueryPerformanceCounter (or RDTSC with proper calibration) instead of millisecond timers. Also reduce numOfTimes while debugging — the nested loops can run a very long time at 0xFFF.

Finally, tidy up the menu/control flow: the call to WriteString immediately after calling a menu handler will print whatever EDX happens to hold unless EDX is set — remove that stray WriteString or set EDX beforehand. Use ReadInt for numeric menu choices (or explicitly compare AL to ASCII digits and consume the CR) and skip the recursive timing when savedNum > 12 to avoid overflow and misleading timings.

These targeted edits preserve registers, clarify intent, and make the timing comparison produce trustworthy results.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.