Version 3 of factorial

Updated 2004-02-08 21:44:01

Richard Suchenwirth 2004-02-08 - Factorial (n!) is a popular function with super-exponential growth. Mathematically put,

   0! = 1
   n! = n (n-1)! if n >0, else undefined

In Tcl, we can have it pretty similarly:

 proc fact n {expr {$n<2? 1: $n * [fact [incr n -1]]}}

But this very soon crosses the limits of integers, giving wrong results.

Weekend reading in an older math book showed me the Stirling approximation to n! for large n (at Tcl's precisions, "large" is > 20 ...), so I built that in:

 proc fact n {expr {
     $n<2? 1: 
     $n>20? pow($n,$n)*exp(-$n)*sqrt(2*acos(-1)*$n):
            wide($n)*[fact [incr n -1]]}
 }

Just in case somebody needs approximated large factorials... But for n>143 we reach the domain limit of floating point numbers. In fact, as Additional math functions points out, the float limit is at n>170, so an intermediate result in the Stirling formula must have busted at 144. For such few values it is most efficient to just look them up in a pre-built table, as Tcllib's math::factorial does.

Incidentally, playing with that, I noticed a bug: as table lookup is guarded with

 if {$x <= [llength $factorialList]} {return [lindex $factorialList $x]}

that function has a blind spot at x=171: it returns "" (list index overrun, should test with < ;-) instead of throwing the error, which it does for x>171...


Playing Joy of course involves factorial too: see that page for an older, Polish take of mine, where the generic recursion construct primrec can be wrapped as

 interp alias {} factorial {} primrec 1 *

and, soon on the Wiki in RPN again, the reverse Polish form

 rpn /factorial {1 /* primrec} def

It may look strange, but it's valid Tcl...


See also Factorial using event loop


Category Concept | Arts and crafts of Tcl-Tk programming