You are here: Surpac Concepts > Macros > TCL > Factorial
GEOVIA Surpac

factorial

These examples give an introduction to the use of the while loop, and extends a basic factorial example to include error management in procedures and scripts.

proc factorial {x} {
  set i 1
  set product 1
  while {$i <= $x} {
    set product [expr $product * $i]
    incr i
  }
  return $product
}
puts "Factorial of 10 = [factorial 10]"

Output

Factorial of 10 = 3628800

Description

The procedure factorial accepts one argument, a number and then calculates the product of all integers from 1 up to and including the number for which the factorial is required.

This is achieved by using a while loop to iterate until the upper limit is reached.

The incr command is used to increment the loop index/multiplier variable.

The expr comamnd is used inside the while loop to successiveley multiply the result of the previous pass through the while loop.

Further suggestions

  • Factorials of negative values are undefined.
    A more robust factorial procedure should return an error if the value for which the factorial is required is negative. Notice how the error command is used to abort the script and report the error.
    			proc factorial {x} {
    			  set i 1
    			  set product 1
    			  if {$x <= 0} {
    			    # test for foolishness
    			    error "Attempt to calculate a factorial of a number <= 0"
    			  }
    			  while {$i <= $x} {
    			    set product [expr $product * $i]
    			    incr i
    			  }
    			  return $product
    			}
    			puts "Factorial of -10 = [factorial -10]"
    			
    		
    	
  • Errors in scripts will cause early termination of the script.
    These errors can be caught so that the error condition does not terminate processing. This example uses the catch command to process the error that ocurrs when an attempt to calculate the factorial of a negative. Note how the text of the error message is caught and how it can be used in the calling procedure.
    			proc factorial {x} {
    			  set i 1
    			  set product 1
    			  if {$x <= 0} {
    			    # test for foolishness
    			    error "Attempt to calculate a factorial of a number <= 0"
    			  }
    			  while {$i <= $x} {
    			    set product [expr $product * $i]
    			    incr i
    			  }
    			  return $product
    			}
    			if {[catch {puts "Factorial of -10 = [factorial -10]"} errortext]} {
    			  puts "Caught the error so that execution can continue"
    			  puts "Error text is \"$errortext\""
    			}
    			
    		
    	
  • Factorials are only defined for integer values.
    A more robust procedure would report an error if a non-integral value were passed as the argument. The procedure as it exists works well with fractional values, it just calculates the factorial to the whole number less than or equal to the value of the argument.
    			proc factorial {x} {
    			  set i 1
    			  set product 1
    			  if {$x <= 0} {
    			    # test for foolishness
    			    error "Attempt to calculate a factorial of a number <= 0"
    			  }
    			  if {$x != [expr int($x)]} {
    			    # test for non integral values
    			    puts "Non integral factorial requested. Proceding to calculate factorial([expr int($x)])"
    			  }
    			  while {$i <= $x} {
    			    set product [expr $product * $i]
    			    incr i
    			  }
    			  return $product
    			}
    			puts "Factorial of 10.6 = [factorial 10.6]"