Definitions

   The factorial of   0   (zero)   is defined as being   1   (unity).
   The   Factorial Function   of a positive integer,    n,    is defined as the product of the sequence:
                 n,   n-1,   n-2,   ...   1 



Task

Write a function to return the factorial of a number.

Solutions can be iterative or recursive.

Support for trapping negative    n    errors is optional.



Related task

   Primorial numbers


Factorial:
;input: D0.W: number you wish to get the factorial of.
;output: D0.L
	CMP.W #0,D0
	BEQ .isZero
	CMP.W #1,D0
	BEQ .isOne
	MOVEM.L D4-D5,-(SP)
		MOVE.W D0,D4
		MOVE.W D0,D5
		SUBQ.W #2,D5		;D2 = LOOP COUNTER.
		;Since DBRA stops at FFFF we can't use it as our multiplier.
		;If we did, we'd always return 0!
.loop:
		SUBQ.L #1,D4
                      MOVE.L D1,-(SP)
		      MOVE.L D4,D1
		      JSR MULU_48		;multiplies D0.L by D1.W
		      EXG D0,D1                 ;output is in D1 so we need to put it in D0
                MOVE.L (SP)+,D1
		DBRA D5,.loop
	MOVEM.L (SP)+,D4-D5
	RTS
.isZero:
.isOne:
	MOVEQ #1,D0
	RTS
MULU_48:
        ;"48-BIT" MULTIPLICATION. 
	;OUTPUTS HIGH LONG IN D0, LOW LONG IN D1
	;INPUT: D0.L, D1.W = FACTORS
	MOVEM.L D2-D7,-(SP)
	SWAP D1
	CLR.W D1
	SWAP D1				;CLEAR THE TOP WORD OF D1. 
 
	MOVE.L D1,D2
	EXG D0,D1			;D1 IS OUR BASE VALUE, WE'LL USE BIT SHIFTS TO REPEATEDLY MULTIPLY.
	MOVEQ #0,D0			;CLEAR UPPER LONG OF PRODUCT
	MOVE.L D1,D3		;BACKUP OF "D1" (WHICH USED TO BE D0)
 
	;EXAMPLE: $40000000*$225 = ($40000000 << 9) + ($40000000 << 5) + ($40000000 << 2) + $40000000
	;FACTOR OUT AS MANY POWERS OF 2 AS POSSIBLE.
 
	MOVEQ #0,D0
	LSR.L #1,D2
	BCS .wasOdd			;if odd, leave D1 alone. Otherwise, clear it. This is our +1 for an odd second operand.
		MOVEQ #0,D1
.wasOdd:
		MOVEQ #31-1,D6		;30 BITS TO CHECK
		MOVEQ #1-1,D7		;START AT BIT 1, MINUS 1 IS FOR DBRA CORRECTION FACTOR
.shiftloop:
		LSR.L #1,D2
		BCC .noShift
		MOVE.W D7,-(SP)
			MOVEQ #0,D4
			MOVE.L D3,D5
.innershiftloop:
			ANDI #%00001111,CCR       ;clear extend flag
			ROXL.L D5
			ROXL.L D4
			DBRA D7,.innershiftloop
			ANDI #%00001111,CCR
			ADDX.L D5,D1
			ADDX.L D4,D0
		MOVE.W (SP)+,D7
.noShift:
	addq.l #1,d7
	dbra d6,.shiftloop
	MOVEM.L (SP)+,D2-D7
	RTS
 