Mathjax

jsxgraph

Factorial Fun


Factorial Fun

 There are many computer programming languages and many more being developed all the time.  Usually the first program when learning a new language is "Hello World!", which outputs the text "Hello World!" to the screen.

For engineers, scientist and mathematicians the next program should be the factorial.  The factorial is symbolized with an exclamation point, !, after a positive integer.  It occurs often in probability and series.  The factorial is the product of all integers from one up to and including the number.

  • 1! = 1
  • 2! = 1*2 = 2
  • 3! = 1*2*3 = 6
  • 4! = 1*2*3*4 = 24
  • 5! = 1*2*3*4*5 = 120
 The factorial increases rapidly showing computer artifacts due to limited precision of numbers.


The following example programs in various computer languages take a number from the user, without checking if it is valid, to keep the code simple, and returns its factorial.  Each example includes an introduction and detailed description.


The following programs have two loops.  A loop is where a section of code repeats by going back to the start of the loop.  The outer loop takes the number from the user and has a test to see if 0 was entered.  The inner loop computes the factorial by multiplying the numbers from 1 to the input number, 'n'.

Languages

Fortran
C Family
Spreadsheets
Shells
Interpreters
X11 Summary

FORTRAN

 FORTRAN is short for formula translation and it was the first successful computer language.  It allowed people to use something similar to standard mathematical formulas to program a computer for performing a calculation.  FORTRAN is still used extensively for computing, because there are many numerical libraries, it is easy to learn, and very efficient at number crunching.   FORTRAN was standardized by ANSI and later ISO/IEC.  FORTRAN 66 and FORTRAN 77 standards were similar, however, Fortran 90, Fortran 95 and on dropped some notation and added new features. The major change was that FORTRAN 77 was fixed format based on Hollerith punched cards that had 80 columns while later versions became free form.  FORTRAN compilers are still supposed to accept FORTRAN 77 input files.  In FORTRAN 77 columns 1-5 are identifier numbers, column 6 is a marker for continuation of the previous line, columns 7-72 are for the program statements and columns 73-80 are for identification information.  Also, a C in column 1 marks a comment line that is ignored by the compiler.  The final identification columns were very useful if the stack of cards was dropped.  FORTRAN also ignores the case so that 'FACTORIAL', 'factorial' and 'Factorial' are the same thing to the compiler. 

FORTRAN 77

 1:      PROGRAM FACTORIAL
 2:C     A program to compute the factorial of a number.
 3:C23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 
 4:      INTEGER*8 K  
 5:C     INTEGER*4 N -- Optional statement 
 6:   20 CONTINUE  
 7:      WRITE(6,300)  
 8:      READ * , N  
 9:      IF ( N .LT. 1 ) STOP  
10:      K=1  
11:      DO 10 I=1,N  
12:       K = K*I  
13:   10 CONTINUE  
14:      WRITE(*,*) N,'! = ',K  
15:      GOTO 20  
16:  300 FORMAT("Enter a number > 0, or 0   
17:     &to quit")  
18:      END  
 Note: the line numbers are not part of the code and should be removed to compile the code. Line Descriptions:
  1. The PROGRAM statement is where the code starts. There must be exactly one PROGRAM statement for any code.
  2. A Comment line ignored by the compiler but tells what the program does.
  3. A comment line I use to track what columns I am using
  4. Define K to be a double precision ( 8 Bytes) number
  5. A comment line ignored by the compiler, by default variables with names begining with i,j,k,l,m or n are single precision integers number
  6. The statement number is and address where the code may go to later. The CONTINUE statement does not do anything but indicates to go on to the next statement
  7. A WRITE statement indicates to write or output to file pointer 6, which is the standard output, using format 300
  8. READ from standard input a number, N. The read is list directed which means the read format is determined from the comma separated list of variables to read
  9. If N is less than 1 stop the program
  10. Set K equal to one, Otherwise K would start as some random number.
  11. DO begins a loop that ends at marker 10. A loop is where the section of code between the DO and the '10 CONTINUE' is repeated. The loop variable I starts at 1 and increases by 1 each loop until it reaches K. 'I' will be N for the last time that the loop is repeated.
  12. The variable K is set to K times I. Each time through the loop K is multiplied by a larger I value.
  13. Marks the end of the loop 10
  14. A List directed write statement which will write (output) according to the type of variable in the comma separated list. Note the text between the quotation marks is output as text. The first star indicates to write to standard output or unit 6.
  15. GOTO sends the program to the statement labeled 20. Note that the statement number does not need to be in order which makes things confusing and GOTO statements are discouraged.
  16. The format for the write on line 5. In this case only instructions are output as text.
  17. The & in column 6 indicates that this is a continuation of the previous line with a space in column 72 after "to"
  18. The end of the program. Only one end statement should be in a program file and a STOP is assumed before the end in FORTRAN 77. A STOP quits the program and an END marks the end of the program source code.
Exercises - Save the code as fact.f Compile the code.  "gfortran fact.f" Run the code " ./a.out" Enter the following numbers 1,2,3,4,5,10,12,13,14,19,20,21,22,64,65,66,100,one Comment out line 4 by putting a C in column 1 and recompile Enter the following numbers 1,2,3,4,5,10,12,13,14,32,33,34,100,one

Fortran 95

In Fortran 90+ the column does not matter. Indentation is to help make the code readable.  At this level there is not much difference between Fortran 90 series and FORTRAN 77 series.
 1:PROGRAM FACTORIAL  
 2:  ! Program to compute the factorial of a number  
 3:  INTEGER (KIND=8) K  
 4:  DO  
 5:    WRITE( *,'(A)',ADVANCE='NO') 'Enter a number > 0 or 0 to quit :'  
 6:    READ *, N  
 7:    IF ( N < 1 ) EXIT  
 8:    K=1  
 9:    DO I=1,N  
10:      K = K*I  
11:    END DO  
12:    WRITE(UNIT=*,FMT="(I6,'! = ',I20)") N,K  
13:  END DO  
14:END  
Line Description
  1. Still only one Program statement per program.  The main entry point and starting place of the program.
  2. Comments start with an exclamation point. It can start anywhere on a line and continues to the end of the line
  3. Named parameters now modify the variable definition.  Kind=8 sets the variable kind to 8 which is an 8 byte length
  4. A 'DO' without anything else starts an infinite loop.  The loop repeats from a matching 'END DO'.  The 'DO' and 'END DO' can have names that must match.
  5. Write to unit * (standard output) with format 'A' ( Text of any length ) and parameter ADVANCE set to no.  With Advance='NO' the program will not go to the next line, but will stay at the end of the line.
  6. List directed read from unit * (standard input) the value for N
  7. Test N and exit the DO if it is less than 1.
  8. Iniitialize K to 1.  If not initialized K would be some random number
  9. Start of the loop with index 'I' increasing from 1 up to and including N
  10. Set 'K' to be 'K' times 'I', The value of K will be changed.
  11. The end of the loop with index 'I'
  12. Write to standard output with format of a 6 digit integer (I6) then the text '! = ', then a 20 digit integer
  13. The end of the do loop without an index,  The code will return to the start of the DO
  14. The END of the program.
Exercises - Save the code as fact.f95 Compile the code.  "gfortran fact.f95" Run the code " ./a.out" Enter the following numbers 1,2,3,4,5,10,19,20,21,22,64,65,66,100 Comment out line 3 by putting an exclamation mark before INTEGER and recompile Enter the following numbers 1,2,3,4,5,10,12,13,14,32,33,34,100

C Family

The 'C' family of programming languages, C,Objective C, Java, C++ have a similar syntax and appearance. They all use curly braces , {}, to group sets of commands. Parenthesis, (), are used for argument (or parameter) list where argument list are passed on to functions. Square brackets, [], are array indecies. Note that in C++ the parenthesis and square brackets can have there meaning changed though overloading.  These languages are case sensitive so that 'main', 'Main' and 'MAIN' are three different functions.

C

'C' is a minimal language with almost limitless capability, but few safeguards or programming aids.  'C' is available on almost all computing devices from embedded processors in toys to Supercomputers.  It is easy to make mistakes in 'C'.  The programmer must be very precise and complete for effective programming.  This language is also very well defined.  Check out http://www.ioccc.org/ for unique 'C' code examples that are very hard to read.
 1:#include <stdio.h>
 2:/* Program for computing the factorial of a number */
 3:int main(int nvar, char** vars) {
 4:  int n,i;
 5:  long long int k;
 6:  while( 1 ) {
 7:    printf("Enter a number > 0, or 0 to quit :");
 8:    scanf("%d\n",&n);
 9:    if( n < 1 ) break;
10:    for(i=1,k=1;i<=n;i++) {
11:      k *= i;
12:    }
13:    printf("%d! = %Ld\n",n,k);
14:  }
15:}
Line Descriptions
  1. Includes the file stdio.h in this file before it is compiled.  stdio.h is the standard input/output header file.  It contains declarations for input and output functions used later.  Header files are usually located in the directory /usr/include, /usr/share/include or some other system location.
  2. A comment begins with '/*' and ends with '*/'.  The compiler ignores everything (except a '/*' - why?) between the symbols.  It can include multiple lines.
  3. This is the start point of all 'C' programs.  The first int indicates that the program will return an integer to the shell.  The arguments nvar and vars pass command line values to the program.  An optional main statement could be 'void main() {' which would ignore command line arguments.
  4. Declares variables n and i to be integers.  An integer has a size that is efficient for the hardware, usually 4 bytes.  All variables in C must be declared, that is have there types defined.
  5. Declares variable k to be at least 8 bytes.
  6. A 'while' will repeat its statement as long as its argument is true.  In 'C' a number other than 0 is true.  This statement will repeat the code between curly braces forever.  Because 1 is always considered true.
  7. This will  output the text.  By default it ends on the same line.
  8. Read from standard input a decimal number and put it in the memory location of n.  In 'C' all arguments are passed as a copy of the value, so we gave the scanf function a copy of the memory location of 'n' rather than a copy of n.  scanf can then change the value at the memory location effectively changing n.
  9. If n is less than 1 leave (break out of) the loop.  This will send the code to line 15 which will then end the program.  Alternatives to the break could be a 'return' or 'exit'.
  10. The beginning of the factorial loop.  The 'for' statement has three parts inside the parenthesis separated by semicolons, ;, The first is an initialization where we set i=1 and k=1.  The next is an exit test performed at the start of the loop.  If this test is false the control will go past the end of the loop.   The third part updates index values.  'i++' indicates to add 1 to 'i' at the end of the loop.
  11. This will replace the value of k with the current value of k times the value of i.  The *= shortens the statement from 'k = k * i'.
  12. This curly brace ends the factorial calculation loop.  The code goes back to line 10.
  13. Write the result to standard output with a format.  In the format %d indicates to write n as a decimal number and %Ld indicates to write k as a long long decimal number.  The %Ld format may not work on all compilers.
  14. This curly brace ends the while loop.  The code goes back to line 6.
  15. This curly brace ends the main function and hence the program.
Exercises - Save the code as fact.c Compile the code.  "gcc fact.c" Run the code " ./a.out" Enter the following numbers 1,2,3,4,5,10,19,20,21,22,64,65,66,100 Remove both longs from line 5 and recompile Enter the following numbers 1,2,3,4,5,10,12,13,14,32,33,34,100 Put the longs back and remove the L from the printf in line 13 and recompile Enter the following numbers 1,2,3,4,5,10,12,13,14,32,33,34,100

 

C Note

The C programming languages are rentrant, that is a method can call itself.  This feature is often illustrated with a factorial computation program such as
#include <stdio.h>
/* Program for computing the factorial of a number */

long long int factorial(int i) {
 if( i == 1) return 1;
 return i*factorial(i-1);
}

int main(int nvar, char** vars) {
  int n;
  long long int k;
  while( 1 ) {
    printf("Enter a number > 0 or 0 to quit :");
    scanf("%d",&n);
    if( n < 1 ) break;
    k = factorial(n);
    printf("%d! = %Ld\n",n,k);
  }
}

This is an inefficient way to compute factorial because each entry into the function 'factorial' has some extra overhead.  In Java with larger numbers this could overflow the stack resulting in a program crash.

 

C++

C++ stands for C plus class.  Classes are an object oriented programming construct that is very useful for separating code into lots of parts.  Object oriented programming is good for graphical interfaces and data centric operations.  For our simple program there is not much difference but in another post including a graphical interface the code will change significantly.  The main difference in is the input and output statements.
 1:#include <iostream>
 2:// Program for computing the factorial of a number
 3:int main(int nvar, char** vars) {
 4:  int n,i;
 5:  long long int k;
 6:  while( 1 ) {
 7:    std::cout << "Enter a number > 0, or 0 to quit :";
 8:    std::cin >> n;
 9:    if( n < 1 ) break;
10:    for(i=1,k=1;i<=n;i++) {
11:      k *= i;
12:    }
13:    std::cout << n << "! = " << k << std::endl;
14:  }
15:}
Line Descriptions
  1. Includes the iostream header for input and output
  2. A one line comment starts with '//' and runs to the end of the line.
  3. The main entry point - see C code line 3
  4. Declarations for n and i
  5. Declaration for k
  6. Begin main loop
  7. std:: is an indicator that the next item is in namespace std.  This is meant to avoid conflicts where an item may have naming conflicts.  We could have named a variable cout which would be different than the cout in the std namespace.  This namespace practice helps to isolate local variables from system or library variables.
    cout is an output stream connected to standard output.
    '<<' sends the next item to the output stream.  How it is sent depends on the item and other formatting information set on the stream.   Note that '<<' is the left shift operator by default.
    By default the stream stays at the last operation.
  8. cin is an input stream connected to standard input.
    '>>' sends data to the next item.  A pointer to the memory location is not needed.   Note that '>>' is the right shift operator by default.
  9. Exit condition test.
  10. Loop for calculating the factorial
  11. k = k * i
  12. end of factorial loop
  13. Sends the value of n, then the string "! = ", then value of k and finally a new line or carriage return to standard output.
  14. end of the main loop.
  15. end of the main function and the program.
Exercises - Save the code as fact.cpp Compile the code.  "g++ fact.cpp" Run the code " ./a.out" Compare what happens in the C++ code with what happens in the C code when you enter "Five". Hint: For console programs a [Ctrl]C will stop a running program.

Java

Java was written to remove many problems in programming C++ by eliminating some features and maintaining stricter object orientation.   Java does not have direct access to pointers and has automatic garbage collection.  One of the major difficulties in C and C++ is memory leaks.  A memory leak is where the program allocates ( or reserves ) memory for a variable but does not properly deallocate (or free) the memory when it is done with the variable.  Another problem is when the memory is deallocated before being done with the variable.  Garbage collection is where the system keeps track of when the variable is no longer needed and will free the memory automatically.  Java also checks array bounds which is a problem often causing segmentation faults in other languages.  Java is partially an interpreted language, that is the code runs one command at a time. Running java code involves two steps, first the code is compiled into "bytecode" with javac, then the bytecode, in a .class file, is run by an interpreter, "java". The interpreter is specific for each platform while the bytecode is independent of the computer platform. The interpreter is probably written in C for each platform. Java is a slow language and uses a lot of memory but it will run on most platforms. Java also has strong security mechanisms so that it is relatively safe to run programs downloaded from the internet, If you do not allow the program extra privileges.
 1:import java.io.*;
 2:class Fact {
 3:    /** Program to compute the factorial of a number*/
 4:    public static void main(String[] args) {
 5:        int i,n;
 6:        long k;
 7:        String nstr;
 8:        try{
 9:            InputStreamReader cin = new InputStreamReader(System.in);
10:            BufferedReader br = new BufferedReader(cin);
11:            while(true) {
12:                System.out.print("Enter a number > 0, or 0 to quit :");
13:                nstr = br.readLine();
14:                n = Integer.parseInt(nstr);
15:                if( n < 1) break;
16:                k = 1;
17:                for( i=1; i<=n; i++) {
18:                    k *= i;
19:                } // for(  i 
20:                System.out.println(n+"! = "+k); // Display the result.
21:           } // while(true)
22:       } catch( IOException ioe) {
23:            System.out.println(ioe);
24:       } finally {
25:            System.out.println("Leaving now!!");
26:       } // try
27:    } // main
28:} // class Fact
Line Descriptions
  1. The import makes classes available to this program.  The star '*' is short for all so this import makes all of the classes in java/io available for this program.
  2. Defines a class named Fact.  The file name should be the same as the main class with a ".java" appended.
  3. A comment.  Comments in java can be multi-line starting with '/*' and ending with '*/' or to the end of the line starting with //.  The special three character start of a comment /** makes the comment appear in the documentation generated with javadoc or Doxygen.
  4. This is the program starting main entry point.  In Java there can a main function in each class.  This is very handy because the main function can be a test function so each class can be executed by itself.  The qualifiers before main are : public - The function or data are available to all other classes in the code.  static - Indicates this is part of the class and there is only one.  When a class is instantiated (created) this is not copied.  Also, the class does not need to be instantiated to use this function or data.
  5. Declares i and n to be of type int,  Numbers in Java are defined to be specific sizes so that an 'int' is always 4 Bytes instead of an efficient size for the hardware.
  6. Declares k to be of type 'long' which is an eight byte integer.
  7. The java io system reads only bytes, characters or Strings.  So the program needs a String object.
  8. Error handling is enforced in Java.  The io methods may throw an exception (error) so our program must define a section of code we will try to run and if it fails we will catch the exception (error) and possibly do something to fix the problem.
  9. The program needs a reader which can take data from a stream and convert it to characters.  System.in is the standard input InputStream.  An InputStream can only read bytes of data.
  10. A BufferedReader can read a line of input as a String object.  This one is connected to the InputStreamReader created in line 9.  So now the BufferedReader sequence is System.in -[bytes]-> cin -[characters]-> br -[String]->.
  11. Begin the outer loop that ends on line 21
  12. Write the prompt to standard output (System.out)
  13. Read a line from the BufferedReader br.
  14. Convert the String nstr to an decimal integer by parsing it.
  15. Test if the user wants to leave the loop and hence the program
  16. initialize the value of k to 1.  The compiler will force the programmer to initialize all variables.
  17. The loop to compute the factorial with i starting at 1 and increasing by 1 each loop until it is not less than or equal to n.
  18. Reset k to be equal to k times i
  19. end of the factorial for loop.  I have added a comment (//) to mark what this curly brace is closing.
  20. Write the result.  println will write a String to the stream.  A String '+' a number will convert the number to a String and add it to the String. Therefore, n+"! = "+k, is a String.
  21. End of the main loop with a comment to indicate what is ended
  22. A catch will run a section of code if an Exception of the type in the catch is thrown in the matching try block.  In other words, if there was a problem in the input/output (IOException) run the following code block .
  23. Write a statement to standard output about what was the problem.
  24. A finally will be ran at the end of the matching try block whether or not an exception happened.
  25. Write that the code is done to standard output.
  26. End of the try/catch/finally code.
  27. End of the main function with a comment
  28. End of the class Fact with an optional comment.
Exercises - Save the code as Fact.java Compile the code "javac Fact.java" Run the code "java Fact" Test various numbers as above. Java has a class for arbitrary precision integers called BigInteger.  The following code uses this class instead of a built-in long integer type for k.
import java.io.*;
import java.math.BigInteger;

class BigFact {
    /** Class to compute the factorial of a number to arbitrary precision*/
    public static void main(String[] args) {
        int i,n;
        BigInteger k;
        String nstr;
        try{
            InputStreamReader cin = new InputStreamReader(System.in);
            BufferedReader  br = new BufferedReader(cin);
            while(true) {
                System.out.print("Enter a number > 0 or 0 to quit :");
                nstr = br.readLine();
                n = Integer.parseInt(nstr);
                if( n < 1) break;
                k = BigInteger.ONE;
                for(i=1;i<=n;i++) {
                    k = k.multiply(BigInteger.valueOf(i));
                }
                System.out.println(n+"! = "+k.toString()); // Display the result.
           } // while(true)
       } catch( IOException ioe) {
            System.out.println(ioe);
       } finally {
            System.out.println("Leaving now!!");
       }
    } // main
} // class BigFact
 
Save the code as BigFact.java Compile the code "javac BigFact.java" Run the code "java BigFact" Test various numbers as above. Note what is in the low order decimal places for 100! and see if this helps to explain the results of 64!, 65! and 66! above.

Spreadsheet Factorials

Spreadsheets can be used for programming computations.  Without scripts or macros a spreadsheet does not have a loop capability.  But, it can perform computations referencing cells to provide a sequence of cells with factorials.  Cells are much like variables in other programming languages, they store values. The figure below shows a spreadsheet programmed to compute the factorials from 1 to 30.  In column A is the number which increases from 1 to 30.  In column B is an equation to calculate the next factorial.  Column C shows the equation that is in column B.  And column D has the result of the spreadsheet function fact().
Entering the equations and numbers could be quite tedious.  Nothing should be tedious on a computer.  All spreadsheets have methods for entering such sequences of equations and numbers.  Note the selected cell, C2, with the outline and small square in the lower right corner.  To enter the sequence of numbers in column A, enter 1 in cell A2 and 2 in cell A3, then select both cells, pause then drag the small square in the corner down to cell A31.  Enter "1" in cell B2 and "=A3*B2" in cell B3.  In cell C3 enter "=formula(B3)", in cell D2 enter "=fact(A2)" and finally in cell D3 put "=fact(A3)".  Exclude the quotation marks in all cell entries.  Then to fill in the remaining cells, select cells B3 to D3, then drag the small corner square down to cell D31. This is from the spreadsheet program "LibreOffice" version 3.6.  If the columns are expanded additional zeros will fill the column.  However, 21! and further are not exact.  21! equals 51090942171709440000 not 51090942171709400000  this indicates that double precision (8 byte) floats are use in computations.  Other spreadsheets, "Calligra Sheets" and "gnumeric" get 21! correct but have errors on 22!. It is possible to have loops in scripts or macros which are programs that run inside the spreadsheet.   The following is a macro function in Star Basic (this should work in MS basic macro also).  After compiling this macro enter "=factorial( ... )" in a cell to obtain the factorial.  Do not enter the quotation marks and "..." can be a cell reference or a number.
1:  Function factorial ( n as Long ) as Double  
2:   k = 1  
3:   for i = 1 to n  
4:    k = k * i  
5:   next i  
6:   factorial = k  
7:  end Function  
Line-by-line description
  1. Start of the function with an argument (or parameter) of "n" that is a long (4 byte integer) with a return value that is a Double ( 8 byte float).
  2. Initialize k to one.  If not initialized k would be zero so the result would be zero.
  3. Begin a loop with index "i" that ends on line 5.
  4. Computation of factorial, setting k = k times i for each i.
  5. Use the next i value and go to the start of the loop, line 3.
  6. The value returned from the function is the same name as the function within the function.
  7. The end of the function.
In "Calligra Sheets" the numbers fill with random numbers instead of zeros.  A little formatting and a Christmas tree can be obtained as shown below.  Oh what fun!

Bourne shell, sh

A shell allows the user to interact with the computer much easier than older methods.  The shell mainly takes care of converting text commands to instructions for the computer.  A shell can operate in different modes including interactive and as a script.  In interactive mode commands go straight to the computer while a script ( or macro) is a file with a sequence of commands that get sent to the computer in sequence.  To be consistent with other of the factorial programs,  these programs will be scripts.  This script will also work with shells derived from sh including bash (Bourne Again Shell) and  kshell (Korn Shell).
 1:#!/bin/sh  
 2:# A program to compute the factorial of a number  
 3:declare -i n  
 4:while true ; do  
 5:  read -p "Enter a number > 0, or 0 to quit :" n  
 6:  if test $n -lt 1 ; then  
 7:    break  
 8:  fi  
 9:  let k=1  
10:  for (( i=1;i<=n;i++ )) ; do  
11:    ((k=$k*$i))  
12:  done  
13:  echo ${n}"! = "$k  
14:done
Line-by-Line description
  1.  # indicates a one line comment line with the special two character sequence "#!" ( sha-bang ) is used to indicate the shell or interpreter for this file.  "/bin/sh" is where the interpreter is on my system it may be in a different place on  your system.  There can also be options for the shell like -v which will repeat lines as they are executed, a method to find out where an error is occurring.
  2. A one line comment stating what the program does.
  3. Optional line to declare that n is an integer.  All variables do not need to be declared unless a prior option to force all variables to be declared is set.
  4. Begin the main loop which goes to the "done" on line 14.  While will repeat as long as it argument is true.  Note- "True" is not true, character case is significant.  Also the semicolon could be omitted if the "do" is on the next line.  Actually the semicolon is the same as a new line to the script or you can think of it as combining lines.
  5. A read command which reads from standard input with a prompt option (-p).  The prompt is our standard question asking for input.  The result of the read is put into the variable "n".
  6. if the the command after the "if" is true then run its "then" statements.  The "test" command  checks a  comparison of number and returns true(1) or false (0).  The '$' before the 'n' indicates to use the value of 'n'.  '-lt' means less than, i.e. is the value of 'n' less than 1.  The semicolon combines the next line.
  7. "break" will leave the while loop thus ending the script.
  8. The end of the "if" instructions, "if" spelled backwards. 
  9. The "let" command assigns values.  Note there are no spaces in the assignment "k=1".
  10. Start a loop, initializing the loop variable i to 1, checking whether the value of i is less than or equal to the value of "n", then add one to the value of "i" at the end of the loop.  'do' the commands until the "done" repeatedly.
  11. The double parenthesis indicate a mathematical operation where the value of "k" is set to the value of "k" times the value of "i".
  12. The end of the factorial loop. Return to the start of the loop.
  13. Write to standard output the rest of the line.  "${n}" is the value of "n" where the braces are optional to isolate it from additional characters.  The quoted text will be echoed without the quotes. Then the value of "k" will be output.
  14. The end of the while loop.  Return to line 4.
Exercises - Save the code above to "fact.sh", see note below. Make the code executable (chmod u+x or use a file manager) Run the code ( ./fact.sh) and enter numbers including 5,10,12,13,19,20,21 and 70 Note: a shell can be used to remove the line numbers easily.  Save the code
#!/bin/sh
sed -i -e 's/^.\{1,3\}://' $1
to a file "unn", make it executable,  and run it with the name of the file with line numbers( ./unn fact.sh ) .  This script runs the stream editor, sed, inplace ( -i ) with the instruction ( -e ) to substitute ( s ) matches of ( / ... / ) the beginning of the line( ^ ) followed by 1 to 3 ( \{1,3\} ) of any character ( . ) followed by a colon ( : ) with nothing ( // ).  This also passes the first argument of the script ( $1 ) as the file for sed to change.

C shell - csh, tcsh

The C shell was intended to have a syntax similar to the popular programming language "C".   "tcsh" added many useful features for interactive use including tab completion and history.
 1:#!/bin/csh
 2:#  A program to compute the factorial of a number
 3:while (1)
 4:  printf "Enter a number > 0, or 0 to quit :"
 5:  set n = $<
 6:  if ($n < 1) then
 7:    break
 8:  endif
 9:  @ k = 1
10:  @ i = 1
11:  while ( $i <= $n ) 
12:    @ k = $k * $i
13:    @ i = $i + 1
14:  end
15:  echo ${n}"! = "$k
16:end 
Line-by-line description
  1. Comment line to indicate the interpreter to use for running this code
  2. A one line comment
  3. Start a while loop - repeat while the parenthesis contents are true.  1 is true.
  4. print formatted the string without a new line
  5. set the value of "n" to what is read from standard input "$<"
  6. Test if the value of "n" ($n) is less than 1 if it is less than 1 execute the commands up to the matching "endif" otherwise skip to past the "endif"
  7. break out of the while loop to quit the program
  8. mark the end of the "if" statements
  9. @ indicates a math operation follows which sets the value of "k" to 1.  The spaces are necessary.
  10. set the value of "i" to 1
  11. start of the factorial loop.  Repeat while the value of "i" ($i) is less than or equal to the value of "n" ($n).
  12. @ indicates a math operation, set the value of "k" to the product of the values of "k" and "i"
  13. A math operation to add 1 to the value of "i"
  14. The end of the factorial while loop.  Return to line 11.
  15. print (echo) the rest of the line to standard output.  The line includes the value of "n" (${n}), the string "! = ", and the valuie of "k".  The braces on "n" are optional but can be used to isolate the name of the variable.
  16. The end of the main while loop.  Return to line 3.
Exercises -Save the code above to "fact.sh", see note below. Make the code executable (chmod u+x or use a file manager) Run the code ( ./fact.sh) and enter numbers including 5,10,12,13,19,20,21 and 70

dc - Desktop Calculator

dc is a stack based  calculator that can be programmed.  dc has been around for a long time and is still useful.  It has only 45 terse instructions so should be easy to learn.  With a stack, items are pushed onto the top of the stack and pulled from the top of the stack.  For example a multiplication takes the top two items, multiplies them together, then pushes the result onto the top of the stack.  Many things are done on computers using stack systems.  Post script and pdf are a stack based system for printing graphically.  dc is a fun way to learn stack based programming because it is an arbitrary precision calculator showing results to many digits.  The programs are usually one liners where almost every character does something.  This code has been expanded to be more readable.  Most of the action occurs on the last line.
 1:#!/usr/bin/dc
 2:[[Enter a number > 0, or 0 to quit :]P]sa
 3:[q]sb
 4:[d[d1-d1<F*]dsFxrn[! = ]Pn[
 5:]P]sc
 6:[lax?d1>blcxdx]dx
Line-by-line description
  1. # starts a comment, #! on the first line indicates the interpreter to use for executing the program
  2. Save the string that when executed will print the instruction to enter a number to standard output.  The string is saved in register "a"
  3. Save the string that will quit the program into register "b"
  4. Lines 4 and 5 compute the factorial and print the results.  The table below shows an example if a three was in the top of the stack at the start of line 4.  These are saved into register "c"
  5. A continuation of the string of instructions from line 4.
  6. The main command sequence.
    1. lax - load register "a" and execute it
    2. ? - read input from standard input
    3. d1>b - test if 1 > the number input and run register "b" to exit if it is true
    4. lcx - load register "c" to compute the factorial and print the result
    5. dx - duplicate the top which will be this string and execute it
    6. [ ... ]dx - duplicate the string for the prior "dx" so that it is available after the factorial and execute (run) the string.
Note that the string in line 2 could be substituted for "lax" in line 6 and "lcx" could be replaced by the string of lines 4 and 5.  The following table show the stack contents after each command of lines 4 and 5 assuming 3 is on the stack at the start.  Additional stack contents including the string of line 6, are not shown as they would just push on down the stack.
    Command Stack After Command Comment

    3 top element of the stack
    d 3 duplicate the top for later output
    3
    [d1-d1<F*] [d1-d1<F*] push the string “d1-d1<F*”
    3
    3
    d [d1-d1<F*] duplicate
    [d1-d1<F*]
    3
    3
    sF [d1-d1<F*] save into register “F”
    3
    3
    x (d1-d1<F*) 3 execute the string
    3
    d 3 duplicate
    3
    3
    1 1 push 1
    3
    3
    3
    - 2 subtract the top from the second
    3
    3
    d 2 duplicate
    2
    3
    3
    1 1 Push 1
    2
    2
    3
    3
    <F 2 if top is less than second ( 1 < 2) execute F
    3
    3
    x (d1-d1<F*) 2 Execute "F", Note that the multiply in the first string has not been used yet.
    3
    3
    d 2 duplicate
    2
    3
    3
    1 1 Push 1
    2
    2
    3
    3
    - 1 subtract the top from the second ( 2-1)
    2
    3
    3
    d 1 duplicate the top
    1
    2
    3
    3
    1 1 Push 1
    1
    1
    2
    3
    3
    <F 1 if top is less than second ( 1 < 1) execute F.

    F is not executed again.
    2
    3
    3
    * 2 multiply top two elements (1*2), This is the second "*"
    3
    3
    * 6 multiply top two elements (2*3), This is the first "*"
    3
    r 3 reverse the first two elements
    6
    n 6 Print and remove the top element
    [! = ] [! = ] push the string “! = “
    6
    P 6 Print the string “! = “
    n
    Print and remove the top element
    [

    ]
    [

    ]
    push a string with a new line in it
    P
    Print the new line
    Exercises - Save the code to a file without the line numbers (fact.dc) Make the file executable (chmod u+x) Run the program (./fact.dc) Enter some numbers including 5,19,20,21,70 Enter "15 3 /" ( without quotation marks) Enter "7 10 *" Enter _3 - On input an underscore is used to represent a negative number since a dash would difference the top two stack items. Restart and enter "2 k 20" Assuming the computer memory is large enough, this code will give "exact" results for all positive numbers except for one number.  Which number gives the wrong answer and why?  Fix the code to give the correct answer for all positive integers.

    bc - Basic Calculator

    Since dc was difficult for some people to use, a more natural "C" like calculator with arbitrary precision was desired.  The original "bc" used "dc"  to perform its computations. This code uses gnu extensions to read "n" and print the results.
     1:#!/usr/bin/bc
     2:/* A program to compute the factorial of a number */
     3:while(1) {
     4:  "Enter a number > 0, or 0 to quit :"; n=read()
     5:  if( n < 1) break;
     6:  k=1;
     7:  for(i=1;i<=n;i++) k=k*i;
     8:  print n,"! = ",k,"\n"
     9:}
    10:quit
    
    Line-byline description
    1. Tell the system to use /usr/bin/bc as an interpreter.  # starts a comment
    2. A multi-line style comment.  A # could also be used for one line comments.
    3. Begin the while loop.  Repeat if 1 is true.  1 is true so repeat forever.  Braces enclose the code to be repeated.
    4. If there is no assignment the result is written to standard output.  Here the question string is written then "n" is read from standard input.
    5. Test if n is less than one break out of the loop.  This also illustrates a one line "if" statement
    6. Initialize k to 1.  It will be 0 if not initialized.
    7. A one line for loop with an index variable of "i" starting at 1 till it is not less than or equal to the value of "n" and increasing by 1 each loop.  Each loop sets the value of "k" to the product of the values of "k" and "i"
    8. print the results to standard output.
    9. end of the while loop,  go to line 3.
    10. quit the program.  Without this statement bc would continue to run after the main loop ended.
    Exercises - Save the code as "fact.bc" Run the code (./fact.bc) Enter some numbers.

    Python

    Python is powerful dynamic programming language. It has a large standard library and huge number of third party libraries. Python integrates well with other languages so that "low level" high efficiency languages can be used where needed. Notable Python packages include scipy, scientific-python, numpy, matplotlib and Sage. Scipy and Scientific python have numerical routines for science and engineering. Numpy includes fast numerical array and matrix operations. Matplotlib is an extensive plotting library. Saga is a very good math toolbox that runs a customized Python for math theory. The developers claim [http://www.python.org/about/] very clear, readable syntax strong introspection capabilities intuitive object orientation natural expression of procedural code full modularity, supporting hierarchical packages exception-based error handling very high level dynamic data types extensive standard libraries and third party modules for virtually every task extensions and modules easily written in C, C++ (or Java for Jython, or .NET languages for IronPython) embeddable within applications as a scripting interface The "clear, readable syntax" takes some getting used to because it does not close or end blocks of instructions with an "END", "}" or ")" but uses indentation. It is also difficult in editors to tell the difference between tabs and spaces which hides indentation level because a tab counts as one space for indentation. There are many differences between Python version 2 and Python version 3. Since Python 2 had some large libraries, many have not yet been ported to Python 3. For this factorial program the main difference is in the print statement.
     1:#!/usr/bin/python
     2:''' A program for computing the factorial of a number '''
     3:while True:
     4:    line = input("Enter a number > 0, or 0 to quit :")
     5:    n = int(line)
     6:    if n < 1 : break
     7:    k=1
     8:    for i in range(1,n+1):
     9:        k *= i
    10:    print n,"! = ",k
    
    Line by Line description
    1. A '# begins a one line comment.  This comment on the first line indicates to use an shell or interpreter to run this program.  If the file is made executable it can be executed with just its name.
    2. A special muti-line comment begins and ends with three quotes.  This text will appear as documentation when a user ask for a description of the program with help().
    3. Begin the main loop.  Continue to run while True is true. Note that capitalization is important and "true" does not equal "True".  But "True" is true.  The loop ends before the next line with the same indentation level or the end of the file.
    4. The "input" function will output the text argument to standard output then read standard input into a string.   Convention is to use 4 spaces for each indentation level.
    5. The "int" function takes a string and converts it to an integer.  Note that there is no type declarations, line is a string and n is an integer but that can change.  We could have written "n = input("En ..." and "n = int(n)".  Any variable can be any type at any time.
    6. Test the value of n and leave the main while loop if n <1
    7. Initialize k to 1
    8. Begin the factorial loop.  Python does not have a typical index variable but will iterate over a list.  The range command will generate a list running from the first number up to (not including) the second number.
    9. Multiply k by i
    10. Indicate the factorial loop has ended by returning to the indentation level of the for clause.  Write to standard output, the value of n, some text then the value of k.  The end of the file ends the main while loop.
    The same code in Python 3 with some added features.
    #!/usr/bin/python3
    ''' A program for computing the factorial of a number '''
    while True:
        line = input("Enter a number > 0, or 0 to quit :")
        try:
            n = int(line)
        except ValueError as err:
            print(err)
            continue
        if n < 1 : break
        k=1
        for i in range(1,n+1):
            k *= i
        print ("{0}! = {1}".format(n,k))
    
    An exception loop has been added that will check if the string input converts to an integer.  The "try:" begins checking for exceptions and if a ValueError occurred print an error message and continue (i.e. return to the start of ) the while loop. The print statement is different, the values to be written must be in parenthesis.  A string format is used where the first format argument is placed at the "{0}" and the second at the "{1}".  Using format removes the space after the value of "n" since a space is added between items in a print statement. Excercises - Save the first and/or second code (without line numbers) to fact.py Make the file excetable, chmod u+x fact.py Run the program, ./fact.py Enter some numbers including 1,5,70,500, five and 0

    Lisp (Common Lisp)

    Lisp or List Programming language was written for artificial intelligence (AI) programming and has a different look. It is primarily a set of list, which are enclosed in parenthesis. The list can be a list of items or it can be a function (or macro). The first item in the list controls what it does. In a linguistic sense, Lisp commonly follows a Verb-Object-Subject sentence structure, which is one of the least common sentence structures in the world with only 3% of languages using it. An example list would be (* 1 2 3 4) which would multiply the values 1, 2, 3 and 4 returning their product. Normally lisp is run in an interpreter where each form is executed one at a time. A form is a list that does some action. Lisp takes some getting used to but provides an approach that is very practical and intuitive for some people. Lisp is also very flexible.  The book "Practical Common Lisp" by Peter Seibel is a good source for learning Lisp.
     1:;;  A program to compute the factorial of a number.
     2:( loop 
     3:  (format *query-io* "Enter a number > 0, or 0 to quit :" )
     4:  (setq n (parse-integer ( read-line *query-io*)))
     5:  (if (< n  1 ) (return) )
     6:  (setq k 1)
     7:  (loop
     8:     for i from 1 to n 
     9:     do (setq k (* i k))
    10:  )
    11:  (format t "~a! = ~a~%" n k)
    12:)
    
    Line by Line description
    1. A comment in Lisp starts with a semicolon, ;. Convention is for normal comments to start with two semicolons and end of line comments to start with single semicolons that are aligned after all program text.  Three semicolons are used for major comments.
    2. "( loop " begins a loop that ends at a matching close parenthesis it will process the instructions in order
    3. The format list will write to a stream with formatted text.  "*query-io* is a global variable marked by the asterisk that points to the standard input and standard output.  This is preferred to direct writing to standard output because "standard output" is often redirected to a file.
    4. "(setq" has three parts, the command setq, the variable name to be set, then the value to store in the variable.  In this case 'n' is the variable and another list (or form) is the value.  The (parse-integer takes a String and converts is to an integer.  In this case the string comes from a '(read-line' which reads a string from the indicated '*query-io* stream.
    5. Note the list with a less than test then the variable n followed be the value 1.  (< n 1) is equivalent to ( n < 1 ) in other languages and returns true if the value of n is less than 1.  The if has a test followed by an action, in this case the action is to return or leave the loop.
    6. Set the value of k to 1.  Note the there is no type specification for k.  Lisp has dynamic typing so k could be set to a string or a stream or anything else for that matter.
    7. Begin the factorial loop
    8. The 'For' is an optional control for the loop.  In this case 'i' will iterate from 1 to n.
    9. The 'do' is still part of the 'for' statement.  The action within the loop is to set k equal to i*k.
    10. End of factorial loop
    11. Write a formatted string to 't'. 't' is short for standard output.  Format instructions begin with tilde, ~.  The '~a' writes the corresponding  item in the list in human readable form.  The ~% ends the line and sets the stream to the next line.
    12. Closes the outer main loop.
    Exercises - Save the code as fact.lisp without the line numbers. Run the code 'clisp fact.lisp' Test various numbers including 5,12,13,14,19,20,21 and 70 Enter 'five' Since Lisp is an interpreted or shell language, the program itself can be made executable (at least on Unix type systems including Linux, BSD, Mac OSX) by adding "#!/usr/bin/clisp" as the first line and adding execute permission to the file (chmod u+x fact.lisp).  Then just entering ./fact.lisp will run the program.  In the added line, "/usr/bin/clisp", can be replaced with the full path of any lisp interpreter you want to use. Currently, major programs written in Lisp are Maxima, a symbolic algebra program and EMACS, an extensible text editor.  Both use their own Lisp dialect slightly different from Common Lisp.  Common Lisp is a Language standard maintained by  ANSI (American National Standards Institute). Note that lisp is often run within a 'SLIME' environment which allows running programs as well as an interactive shell. The interactive shell is sometimes called REPL for read-eval-print loop and SLIME is Superior Lisp Interaction Mode for Emacs.

    R

    R is more than the answer to questions on Speak like a Pirate Day. R is an extensive data analysis system using vectors, arrays, matrices, list and data-frames. A data-frame is like a database table. R can perform all kinds of statistical analysis on these data types. Several packages are available to enhance R.
     1:#!/usr/bin/Rscript --vanilla 
     2:# Program for computing the factorial of a number
     3:n <- 1
     4:while ( n > 0 ) {
     5:  cat("\nEnter a number > 0, or 0 to quit :")
     6:  n <- scan(file("stdin"),what=integer(),n=1,quiet = TRUE)
     7:  if( n > 0 ) {
     8:    k <- prod( 1:n )
     9:    cat(n,"\b! =",k,'\n')
    10:  }
    11:}
    
    Line-by-Line description
    1. Rscript is a command to run R scripts it may be located somewhere else on your system. The option --vanilla tells Rscript to just run the script - don't save or restore the session or read system startup files.
    2. A comment starts with a # and runs to the end of the line. Comments can start anywhere on the line.
    3. Sets the variable n to the value 1, n is then a vector with one element. The left arrow "<-" is the default assignment operator. The "=" can also be used as well as a right arrow "->" with the assignment to the right side. This line could be "n = 1" or " 1 -> n ".
    4. Begin the main entry loop. Repeat everything between matching braces "{" and "}" while the statement n > 0 is true.
    5. cat is short for concatenate which combines its parameters on standard output.
    6. set n from standard input, explicit setting of standard input, file("stdin"), is required because Rscript is reading the script from its standard input. n=1 tells scan to read one item, the rest of the input (after white space) is discarded
    7. if n is greater than 0 execute the statements within matching curly braces "{" and "}". Semicolons can be used to separate statements on the same line.
    8. k is set to be the result of the prod function which takes a vector and multiplies the elements. The 1:n creates a vector with the numbers 1 to n. A alternative function is gamma(n+1) which returns the gamma function. The gamma function of n+1 equals n! for positive integers.
    9. output the result with the cat function. cat separates each entry with a space by default so a backspace "\b" is necessary to place the exclamation mark next to the number n. The \n character starts a new line.
    10. end of the if statements
    11. end of the while loop
    Exercises: Save the code as fact.R Make the code executable ( chmod u+x fact.R ) Run the code with ./fact.R Try numbers - 5,7,12,13,22,69,70 Quit and restart R with "R" enter> source("fact.R") try some numbers enter 0 enter> options(digits=22) enter> source("fact.R") try some numbers quit by entering > q() change line 8 to : k <- gamma( n+1) run again add "options(digits=22)" after line 2 run again

    Factorial with a X Windows user interface

    With this post I looked at programming for the X Window System (X11). X11 is hardware-independent application programming interface (API) for graphical user interface (GUI) programming that includes commands for drawing to a screen and user interaction through key board, mouse or other input devices.   The interface provides a means for software to communicate with graphics hardware including over a network.  X11 was designed with local GUI interaction for programs running on a remote computer as a major issue.  The X Window System was started at Massachusetts Institute of Technology (MIT) in 1984 and quickly became the de facto standard for networked workstations.  The X Window System is constantly being improved, but the default X11 is a pixel based system which produces ugly text without anti-aliasing.   A pixel based system draws a color to pixels so that object edges appear jagged.  Anti-aliasing reduces the jagged edges by drawing varying colors around the border of objects to blend the object color with the surrounding colors.  To access the code which is amply commented see the post C code for factorial program using X11, Xft and GMP.  A screen shot of the program with anti-aliased fonts.
    This program started to be a simple factorial program like the prior post but quickly grew.  The original concept was a simple line of instructions followed by the "n! = answer" string.  However, since the string is drawn into a window, it made sense to draw multiple lines that could fit within the window.  Since the answer could have many digits, an automatic reduction of font size and wrapping of the solution was programmed.   This involved tracking the window and character sizes.  Three font sizes were made available, using the biggest one that fit within the window.  Another original concept was to use the Gnu Multi-Precision (GMP) library to calculate larger factorials correctly if it is available. X11 uses an event loop to wait for user interaction.  A means of using this loop to enter numbers was designed.  Other options were added by looking for other keys on the keyboard. The ugly default X11 fonts needed improved so the Xft library was used.  When running over a slow network with high latency the Xft library would be slow. Because in order to draw a string, first a snapshot of the background is taken then transferred to the server, then anti-aliased fonts are drawn on the snapshot, then the snapshot is transferred back to the client.  A lot of extra network traffic.  Both display options were included so they could be toggled to compare network response and appearance. Several of the prior post also showed the danger of limited integer size.  To show the impact of integer size an option to reduce the integer size was added.  This option used bit mask to reduce the size so all solutions are non-negative.  The integer size limit and resulting numbers can be made clearer in hexadecimal or binary numbers since these better represent the number within the computer. This program includes many options and optionally depends on two libraries, Xft and GMP.  The code also includes lots of comments to be instructional.  The Xft library (X FreeType interface) provides nice looking anti-aliased fonts and the GMP (Gnu Multi-Precision) library provides arbitrary precision math.

    Preprocessor Directives 

    Whether or not to use the libraries is controlled by the lines
    
    /** define USE_XFT for antialiased fonts with the Xft library*/
    #define USE_XFT
    
    /** define USE_GMP for arbitrary precision math */
    #define USE_GMP
    Which define 'variables' used by the C preprocessor which changes the code before compiling it based on special commands starting with a hash '#'. Some common preprocessor commands are:
    
    #include < ... >
    #include " ... "
    
    which copies the named file into the source code.  The < ... > starts the search for the file in system level directories and the " ... " starts in the source code directories.
    
    #define USE_GMP
    #define VALUE 5
    #define MIN(X,Y) (((X) < (Y)) ? (X) : (Y))
    
    which define a variable. A variable can optionally be defined with a value as in the second line. With this definition for VALUE the code "y = x + VALUE" would get replaced by "y = x + 5" before compiling. The variable may also be function like, as in the third line where the code "y = 4*MIN(x,5)/3" would get replaced by "y = 4*(((x) < (5)) ? (x) : (5))/3" before compiling. Note that this is a text substitution so it is not a real function and extra use of parenthesis are required to prevent side effects. The tertiary command ( ... )? ... : ... is a short "if else" expression where if the parenthesis contents are true the expression before the colon (:) is evaluated and if the expression is false (0) the expression after the colon is evaluated. These variables can also be defined with compile line arguments "-D...". "gcc -D USE_GMP" would define USE_GMP. The source code #define will override the command line defines and un-defines (-U...).
    
    #ifdef USE_GMP
    ...
    #else
    ...
    #endif
    
    
    #if (VALUE > 4)
    ...
    #elif VALUE < 6
    ...
    #endif 
    
    where the first code block would test USE_GMP and include the code up to an #else, #elif, or #endif if it is defined. The code after the #else would be included if USE_GMP is not defined. Optionally a #ifndef would test if USE_GMP is not defined. The next code block performs test on the value of VALUE and includes the first block if VALUE is greater than 4 and the second block if VALUE is less than 6 but not greater than 4.

    Compiling the code

    In order to use the libraries, the header files for declaring the variables and routines needs to be included in the source code and the library needs to be included in the last phase of compiling (linking). To link with a shared object (DLL or .so) include a -l option with the library name. For this code including the USE_XFT and USE_GMP defines, " -lX11 -lXft -lgmp " will link with the libraries. When shared object linking is used the system the code is run on needs to have the libraries installed. Another option is to use static linking where the library binary code is included in the executable produced. To use this option include the library archive file on the command line. The library archive file ends with a ".a" for example "/usr/lib64/libgmp.a" is name of the GMP archive library file on my system. The full compile line on my computer was gcc factX.c -g -o factX -I/usr/include/freetype2 -lXft -lX11 -lgmp The -g enables debugging by including references to source code statements in the executable file. The "-o factX" names the output executable file factX. The -I/usr/include/freetype2 adds the specified directory, "/usr/include/freetype2" to the search path for include files. Without the -I a compile error fatal error: freetype/config/ftheader.h: No such file or directory was produced. By using locate ftheader.h the location of the file was found to be /usr/include/freetype2/freetype/config/ftheader.h which was used to add the search path to the compile line. Similarly locate libgmp.a gave the location of the library archive for GMP. So the compile command gcc factX.c /usr/lib64/libgmp.a -o factX -I/usr/include/freetype2 -lXft -lX11 static linked the GMP library. The executable file grew in size by over 18 times but the GMP library would not be required on the system the code is run on.  Most modern systems include X11 and Xft by default so they would not need to be static linked.  Also, these libraries require other libraries not required on the compile statement. The compile command can also be used to define variables used by the preprocessor  with the -D option such as gcc factX.c /usr/lib64/libgmp.a -o factX -D USE_GMP -I/usr/include/freetype2 -lXft -lX11 however any #define within the code will override command line options.

    GMP factorial

    The GMP parts of the code are enclosed between a #ifdef USE_GMP and a matching #else or #endif.  Important lines of code for calculating the factorial are:
    • #include <gmp.h>
      -
    • mpz_t k;
      - mpz_t is the variable type for multi-precision integers.  Mathematicians use Z to represent the set of all integers

    • mpz_inits( k, kt, bmask, NULL );

      - Initialize the mpz_t variables in the list ended by a NULL, mpz_t variables must be initialized before they are assigned a value

    • n = atol(text);

      - convert ascii "text" to a long int

    • mpz_fac_ui( k, n );

      - Compute the factorial of the long integer provided and store it into the mpz_t variable
    Additional elements for reducing number precision:
    • switch(precision) {
      - Switch to the code with a case of the value of "precision"
    • mpz_set_ui(bmask,0xff);
      - Set bmask to the Hex number ff, ff in hexadecimal is 8 1 bits in binary, 11111111, or 255 in decimal.
    • mpz_set_str(bmask,"ffffffffffffffff",16);
      - Most 32 bit computers have a long int of only 4 Bytes, therefor a string representation is used for 8 Bytes of 1 bits. Each two hex digits is a Byte.
    • mpz_and(kt,k,bmask);
      - Logical bitwise AND,  Value in ROP is set to bitwise AND of values in OP1 and OP2.  Bitwise AND takes each pair of bits, if both are 1 the resulting bit is set to 1 and 0 otherwise. For example 10101010 & 1111 gives 1010.
    • mpz_set(k,kt);
      - This just copies the value of kt into k for later use
    And to convert the number to a string in the various number bases:
    • switch(showBin) {
      - Switch to the code with a case of the value of showBin
    • case 0: fact = mpz_get_str(NULL,10,k); break;
      - Convert k to a string with base of "base".  If the first argument is NULL a newly memory allocated string is returned, otherwise the result is placed into the char * array provided, which the caller must assure is allocated large enough to hold the result.
    And don't forget to release the internal memory of the mpz_t variables.
    • mpz_clears ( k, kt, bmask, NULL);
      - Release the internal memory used by the mpz_t variables

    X11 Drawing

    Drawing text in X11 involves three phases.  Initialization, listening + drawing and releasing resources. Key elements of the initialization routine, init_x().
    • dis = XOpenDisplay((char *)0);
      -Get the display,  An X11 display can consist of multiple screens (monitors) and input devices (keyboard, mouse, touch screen).  A display can be thought of as a workstation.
    • win = XCreateSimpleWindow(dis,DefaultRootWindow(dis),0,0,400, 247, 0, black, white);
      - This creates a new window at (0,0) that is 400 pixels wide by 247 pixels high with a 0 width black border and white background.  If a window manager is in use, these settings are just suggestions to the window manager.
    • XSetWMProperties(dis,win,winTitle,iconTitle,NULL,0,NULL,NULL,NULL);
      - This tells the window manager more information about what is desired for the window.  Again these are suggestions or hints about what is desired.  The only values set are the window title and icon title.
    • XSelectInput(dis, win, ExposureMask|KeyPressMask);
      -  Tell the X11 server we are interested in Key Press and Window Exposure events.  Key press events are returned when a key is pressed and exposure events are returned when a portion of the window needs to be redrawn because the window size changed or was raised above an obstruction.
    • gc=XCreateGC(dis, win, 0,0);
      -  X11 itself does not store information between draw actions.  The graphics context stores color, font and other information required for drawing.
    • XSetBackground(dis,gc,white);
      - This will be the color behind what is being drawn.
    • XSetForeground(dis,gc,black);
      - This will be the color of the shape to be drawn.
    • XClearWindow(dis, win);
      -  Reset the window to be empty.
    • XMapRaised(dis, win);
      - Very important - This actually shows the window on the screen.
    • smallFont = XLoadQueryFont(dis,"-*-*-*-*-*-*-9-*-*-*-m-*-*-*");
      - This gets font information from the X11 font server.  In this case, a 9 pixel high font that is mono-spaced is requested.
    Key elements of the listening part within the main() function
    • while(1) { - This begins the main loop which will repeat until some other exit request is encountered
    • XNextEvent(dis, &event);
      - Wait for an event to occur.  When it occurs stor information about the event into the structure event
    • if (event.type == Expose && event.xexpose.count==0) {
      - The type of event was an exposure event and it is the last expose event.  Wait for the last expose event to avoid excessive redrawing slowing response time.   A larger program may try to find what portion of the window was exposed and draw only that portion to improve response time.
    • if (event.type == KeyPress) {
      - The type of event was a key press
    • key = XLookupKeysym(&(event.xkey),0);
      - Find out which key was pressed
    • switch( key ) {
      - Got to case statement with the key symbol value
    • case XK_???
      - Every key has a #defined number,  the number is represented by a symbol beginning with XK_.  An XK_KP_ is a key pad key.  There are case statements for both upper and lower case keys.  Since case statements fall through multiple case statements can execute the same code.
    • redraw(text);
      - An event has occurred so redraw the window contents.  "text" is a character array with the string representing the number.
    Key elements of the drawing part in the redraw(text) and draw(numfeq,fact) routines.
    • void redraw(char * text)
      - Computes the factorial, then sets the strings numfeq and fact to contain "n! = " and the solution respectively.
    • draw(numfeq,fact); - This routine draws the instruction string at the top, the "numfeq" string and the "fact" string in multiple lines.
    • instr = nowShowing(); - Get the instruction string. It simplifies the code to move some parts to other routines.
    • XSetFont(dis,gc,smallFont->fid);
      - Put font data into the graphics context
    • XDrawString(dis,win,gc,x,y, instr, strlen(instr) );
      - Draw the string, "instr" at position (x,y)
    • xstart = 5 + XTextWidth(font,numfeq,strlen(numfeq));
      - Calculate the x starting position for the multiple lines of the solution string, "fact"
    • nchar = awid/font->max_bounds.width;
      - Calculate the number of characters that can fit on a line.  "awid" is available width and "maxbounds.width" is the font character maximum width.
    • nlines = totchar/nchar + 1;
      - This is where integer division truncation is used to compute the number of lines required to display the solution
    • if(nlines > maxlines ) {
      - The display of the solution will not fit so try a smaller font.  
    • for(start = 0; start < totchar; start += nchar) {
      - A loop to draw each line
    • XDrawString(dis,win,gc,xstart,y, fact+start, nchar); - Draw  up to nchar characters starting at the fact[start] character.  This uses some pointer math where "fact+start" points "start" characters past the "fact" location.
    • y += font->ascent + font->descent + 5;
      - Compute the y position of the next line.
    The resources are released in the close_x() routine.  Since this is called just before the program exits, these resources don't necessarily need to be released, but it is a good idea to not count on the Operating System to release the resources and it is good practice to release your own resources.  The resources released include the font structures, graphics context, window and display.  They are released in reverse order from their creation.

      Xft Drawing

      The Xft drawing routines are on top of the X drawing routines so much of the X drawing activities must still be accomplished. In addition to the X drawing initialization the following are added:
      • smallXft = XftFontOpenXlfd(dis,screen,"-*-*-*-*-*-*-9-*-*-*-m-*-*-*");
        - Lookup and setup the font, used instead of XLoadQueryFont for X11 drawing. Xft has other font lookup routines that are easier to read because they set values rather than rely on position in a string
      • cmap = DefaultColormap(dis,screen);
        - The color map indicates what colors can be used for drawing
      • drawXft = XftDrawCreate(dis, win, DefaultVisual(dis, screen), cmap);
        - The XftDraw is kind of like the graphics context for X11 combined with the display and window
      • colorXrender.red = 0; colorXrender.green = 0; colorXrender.blue = 0; colorXrender.alpha = 0xffff;
        - The color for drawing is specified with 2 Byte values for red,green,blue and alpha. Alpha is the opacity so alpha = 0 is transparent
      • XftColorAllocValue(dis,DefaultVisual(dis,screen),cmap,&colorXrender,\
        &colorXft);

        - Setup the color "colorXft" for actual use later
      Replacements for the X11 string drawing and size routines are:
      • XftDrawString8(drawXft,&colorXft,smallXft,x,y,instr,strlen(instr));
        - Draw the string at position (x,y). Other string drawing routines are available for Unicode (16 bit) and larger (32 bit) character types.
      • XftTextExtents8 (dis,font,(FcChar8 *)numfeq,strlen(numfeq),&extents);
        textWidth = extents.width;
        textHeight = extents.height;

        - The function XftTextExtents8(...) computes the bounds of the string if it were drawn in the font on the display and puts them into the structure "extents". The width and height are then available from the structure.
      Additional releasing functions are:
      • XftFontClose(dis,smallXft);
        - Free memory used for fonts
      • XftDrawDestroy(drawXft);
        - Release memory used for Xft drawing

      Code Usage

      When the code is started a window appears with limited instructions.  It listens for key presses and responds with the following
      • Any number key (0-9) - adds the digit to the number used for the factorial
      • [Delete] or [Backspace] - remove the last digit from the number
      • [Return] or [Enter] - Clear the number, display is not refreshed immediately.
      • 'A' or 'X' will toggle display text anti-aliasing with the Xft library
      • 'B' will cycle through decimal, binary and hex display of the solution
      • 'P' will cycle through# of bytes precision of the solution - full,8,4,2,1
      • 'Q' or 'Escape' will cleanly exit the program

      Assignments

      Compile the code without using the GMP library.  Test a few numbers.  Toggle font anti-aliasing. Compile with the GMP library.  Test a few numbers.  Change the window size, height and width. Reduce the precision with 'p'. What is the low precision result for larger number values. Change the number representation with 'b' and reduce the precision with 'p'.  Compare with prior post exercises where fixed size integers were used. The two draw routines have a lot of code repeated.  Rewrite the logic for selecting the font size by adding global character sizes calculated in init_x.  Combine the draw routines to simplify the maintenance with useXft logic inside the routines.

      Javascript / HTML

      Another option is to provide interaction within a web browser. The standard script language for web pages is Javascript. Javascript is not Java though it looks a lot like Java and C or C++. Javascript is code that can be enclosed in HTML. HTML (HyperText Markup Language) is used to tell web browsers what is to be shown.

      HTML basics

      The fundamental element to HTML is the tag. A begining tag starts with a < symbol then a type identifier possibly followed by some options and closed with a > symbol. The tag starts an item while a matching closing tag with </ followed by the identical type identifier and a > symbol marks the end of the item. A few common tags are
      <head> The header containing information about the document </head> <title> Title for the web document should be inside the header </title> <script> A section of Javascript code </script> <body> The main content of the document. The closing tag should be at the end of the document contents. </body>

      <h1>Top Level Heading</h1>

      <h2>Second Level Heading</h2>

      <h3>Third Level Heading</h3>

      <ol>ordered list
      1. <li>followed by </li>
      2. <li> any number </li>
      3. <li>of list items</li>
      </ol> <ul>unordered list
      • <li> followed by</li>
      • <li> any number </li>
      • <li> of list items</li>
      </ul> <a> An anchor that identifies a link This links to the start of the Javascript section using an href option.
      A good place to find more HTML information is the World Wide Web Consortium (W3C) tutorials

      Javascript

      Javascript is a computer language based on Java that has access to web browser information and can interact with the browser. Javascript code is executed by the browser. Different browsers may give different results. The performance of Javascript would be inadiquate for heavy computing task but OK for smaller problems. Below are two different implementations of factorial in Javascriot with line by line descriptions. The first one uses input item interation and the second one uses the newer HTML5 forms protocol to update the answer. In the first sample the input items "oninput" parameter calls the fact() function which resets the result paragraph. The Javascript function gets its values from the HTML elements and writes the results to HTML elements. HTML with Javascript
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      <!DOCTYPE html>
      <html>
      <head>
      <meta charset="UTF-8">
      <title>Factorial Calculation Using Javascript</title>
      <script>
      function fact() {
          var num = parseInt(document.getElementById("inp").value);
          var result = document.getElementById("result");
          if( isNaN(num)) {
           result.innerHTML = "Invalid Number Entry -- Try Again"
            return;
          }else if(num < 0){
            result.innerHTML = "Number must be 0 or greater"
            return;
          }
          var res = 1;
          for (i=2; i<=num; i++ ) {     
        res *= i; 
          }
          result.innerHTML = num+"!  =  "+res;
          return;     
      }
      </script>
      </head>
      
      <body>
      <h1>Factorial Using Javascript</h1>
      Enter a natural number to compute the factorial of :
      <input type="number" id="inp" min="1" step="1" value="2" oninput="fact();">
      </br>
      <h2 id="result">2!&nbsp; =&nbsp; 2</h2>
      
      
      
      </body>
      </html> 
      
      Line-by-Line description
      1.   Identifies the document type for the browser
      2.   Marks the beginning of the HTML
      3.   Marks the beginning of the document header
      4.   Identifies the character encoding, UTF-8 is pretty standard for western computers
      5.   The title should appear in the browser address bar
      6.   Begin the Javascript
      7.   Start a function called "fact" with no inputs
      8.   Define the variable num and set it to the integer decoded (parsed) from the text "value" of the element with an Id of "inp"
      9.   Define another variable called result and set it to the element identified as "result"
      10.   Test is the number "num" is not a valid number (NaN = Not a Number)
      11.   If the number is not valid set the result to indicate you need a valid number
      12.   Leave the function an d return to where the function was called
      13.   The else means the number is a valid number, then test if the number is less than 0
      14.   Set the result to indicate a number must be positive or zero
      15.   Leave this function and return to where the function was called
      16.   This marks the end of the "if" series
      17.   Define a new variable "res" and set its value to 1
      18.   Begin a loop with an index variable of "i" that starts with i=2 and continues until i is greater than num ( i<=num;) and increasing by 1 each loop (i++)
      19.   Multiple the current value of res by the index variable i and save the value into res
      20.   The curly brace marks the end of the loop started on line 18
      21.   This is the output by setting the HTML of result to a string starting with the value of num then with a string of "! = "followed by the value of the result.
      22.   This curly brace marks the end of the function fact()
      23.   The end of the script section or element
      24.   The end of the head part of the document
      25.   blanks are ignored
      26.   The beginning of the document contents
      27.   A first level heading for the page
      28.   A description text for the page
      29.   An HTML input item, The item will be a number and when data is entered the Javascript function "fact()" will be called
      30.   Add a blank line to the output
      31.   Use a heading 2 format to display the result. The contents of theis element will be changed by the Javascript function. Initially it will contain 2! plus some extra space (  = non breaking space) then = and more space then 2
      32.   blanks are ignored
      33.   blanks are ignored
      34.   blanks are ignored
      35.   The end of the contents of the page
      36.   The end of the HTML document

      HTML using the form elements. The Javascript function in this page calculates and returns the factorial. While the form itself takes care of setting the result text. Key items are the form "oninput" and the output items "for" parameter.
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      <!DOCTYPE html>
      <html>
      <head>
      <meta charset="UTF-8">
      <title>Factorial Calculation Using Javascript</title>
      <script>
      
      function fact2(number) {
       if( isNaN(number)) {
           result.innerHTML = "Invalid Number Entry -- Try Again";
           return 0;
         }
          var res = 1;
          for (i=2; i<=number; i++ ) {
        res *= i; 
          }
          return res;     
      }
      </script>
      <style>
      #inp {font-size: 1.0em;width: 4em;height: 1.1em;}
      form {font-size: 2.0em;font-family: sans-serif;}
      </style>
      </head>
      
      <body>
      <h1>Factorial Using Javascript</h1>
      <h2>Enter a natural number to compute the factorial of it.</h2>
      </br>
      <form id="factForm" oninput="result.value=fact2(parseInt(inp.value))">
        
        <input type="number" id="inp" min="0" step="1" value="2" >
        ! = <output name="res" id="result" for="inp">2</output>
        
      </form> 
      
      </body>
      </html> 
      
      1.   Identifies the document type for the browser
      2.   Marks the beginning of the HTML
      3.   Marks the beginning of the document header
      4.   Identifies the character encoding, UTF-8 is pretty standard for western computers
      5.   The title should appear in the browser address bar
      6.   Begin the Javascript
      7.   Start a function called "fact2" with number as the input
      8.   Test if the number "num" is not a valid number (NaN = Not a Number)
      9.   If the number is not valid set the result to indicate you need a valid number
      10.   Leave the function and return to where the function was called with a value of 0
      11.   This marks the end of the "if" statement
      12.   Define a new variable "res" and set its value to 1
      13.   Begin a loop with an index variable of "i" that starts with i=2 and continues until i is greater than number ( i<=number;) and increasing by 1 each loop (i++)
      14.   Multiple the current value of res by the index variable i and save the value into res
      15.   The curly brace marks the end of the loop started on line 14
      16.   The function returns the value of res
      17.   This curly brace marks the end of the function fact2()
      18.   The end of the script section or element
      19.   Here I have added some style elements to change the appearance of some of the elements. This begins the style section.
      20.   The "#" indicates a style for the Id following (inp). I changed the font-size, width, and height based on the default character full space size (em). The inp font size is relative to the form font-size.
      21.   Change the style for elements within the form to make the result larger than normal text.
      22.   End the style section
      23.   The end of the head part of the document
      24.   blanks are ignored
      25.   The beginning of the document contents
      26.   A first level heading for the page
      27.   A description text for the page in heading 2 style
      28.   A break to add a blank line
      29.   A form block begins hear, Normally form data gets sent back to a server but that is not necessary. The "oninput" parameter sets the result value to the value returned from the function fact2 with an integer representation of the value of inp.
      30.   Blank lines are ignored
      31.   An HTML input item, The item will be a number
      32.   Some text "! = " followed by an output element linked with the input element inp.
      33.   blanks are ignored
      34.   The end of the form section
      35.   blanks are ignored
      36.   The end of the contents of the page
      37.   The end of the HTML document
      To run the HTML code save to a file with extension .html or .htm and open with your browser using open file or file:/// in the address bar.

      Summary

      Computer representation of numbers

      The key issue with large numbers like factorials, is how they are represented on the computer.  For performing mathematical operations the computer hardware has fixed size numbers.  For integer number types, this is related to the size of registers and number of wires connecting devices.  Each bit of a number is held in a flip-flop.  A flip-flop is an electronic device with two stable states, one representing a 0 and the other a 1. Two types of integers are signed and unsigned.  Unsigned integers are represented in straight binary based numbers.  While signed integers are represented in twos compliment.  To change signs in twos compliment, invert (compliment) all bits then add one.  The following table shows four bit binary numbers and their values for both signed and unsigned integers. 
      8 bit
      Sign bit
      4 bit 2 bit 1 bit Unsigned Signed
      0 0 0 0 0 0
      0 0 0 1 1 1
      0 0 1 0 2 2
      0 0 1 1 3 3
      0 1 0 0 4 4
      0 1 0 1 5 5
      0 1 1 0 6 6
      0 1 1 1 7 7
      1 0 0 0 8 -8
      1 0 0 1 9 -7
      1 0 1 0 10 -6
      1 0 1 1 11 -5
      1 1 0 0 12 -4
      1 1 0 1 13 -3
      1 1 1 0 14 -2
      1 1 1 1 15 -1
      An interesting thing with these four bit signed numbers is that seven plus one is negative eight.  Also, for the unsigned numbers 15 plus one is zero.  The same thing happens with larger number formats but at different numbers.  This is also an issue when comparing signed and unsigned integers because -1 (signed) equals 15 (unsigned) for the four bit numbers above.  The table below shows various numbers and the result of adding one.
      Precision
      Value
      (Signed Value)
      Unsigned
      +1
      Signed
      +1
      1 Byte
      127
      128
      -128
      1 Byte
      255  (-1)
      0
      0
      2 Bytes
      32767
      32768
      -32768
      2 Bytes
      65535  (-1)
      0
      0
      4 Bytes
      2147483647
      2147483648
      -2147483648
      4 Bytes
      4294967295  (-1)
      0
      0
      8 Bytes
      9223372036854775807
      9223372036854775808
      -9223372036854775808
      8 Bytes
      18446744073709551615 (-1)
      0
      0
      This is how numbers are represented in hardware on a computer.  Memory addresses are also represented by fixed length binary numbers and the same issues can arise.  The memory addresses are usually unsigned so an index of -1 typically results in a segmentation fault because it is translated into a very large unsigned number. The hardware is very fast at arithmetic but software can also be used to extend the number range or change the behavior.  The Gnu Multiple Precision Arithmetic Library (GMP) uses several integers internally to represent single larger integers.  This is very slow compared to hardware arithmetic.  Some hardware arithmetic is still used internally by the library.

      Factorial Results

      The C program for factorial was revised to calculate and print using different precision numbers.  Both signed and unsigned numbers were used.  The signed results were printed first with char, short int, int, long int, long long int variables.  The corresponding unsigned values were printed below.  Your results may vary because the C standard does not specify a precision for the variable types, except for char which is one byte.  The results for several factorials are listed below.
      Bytes    1       2       4               8                       8
      Enter a number > 0, or 0 to quit :5                                                    
      5!      120     120     120             120                     120                                            
              120     120     120             120                     120                                            
      Enter a number > 0, or 0 to quit :6                                                    
      6!      -48     720     720             720                     720                                            
              208     720     720             720                     720                                            
      Enter a number > 0, or 0 to quit :7                                                    
      7!      -80     5040    5040            5040                    5040                                           
              176     5040    5040            5040                    5040                                           
      Enter a number > 0, or 0 to quit :8                                                    
      8!      -128    -25216  40320           40320                   40320
              128     40320   40320           40320                   40320
      Enter a number > 0, or 0 to quit :9
      9!      -128    -30336  362880          362880                  362880
              128     35200   362880          362880                  362880
      Enter a number > 0, or 0 to quit :10
      10!     0       24320   3628800         3628800                 3628800
              0       24320   3628800         3628800                 3628800
      Enter a number > 0, or 0 to quit :11
      11!     0       5376    39916800        39916800                39916800
              0       5376    39916800        39916800                39916800
      Enter a number > 0, or 0 to quit :12
      12!     0       -1024   479001600       479001600               479001600
              0       64512   479001600       479001600               479001600
      Enter a number > 0, or 0 to quit :13
      13!     0       -13312  1932053504      6227020800              6227020800
              0       52224   1932053504      6227020800              6227020800
      Enter a number > 0, or 0 to quit :14
      14!     0       10240   1278945280      87178291200             87178291200
              0       10240   1278945280      87178291200             87178291200
      Enter a number > 0, or 0 to quit :15
      15!     0       22528   2004310016      1307674368000           1307674368000
              0       22528   2004310016      1307674368000           1307674368000
      Enter a number > 0, or 0 to quit :16
      16!     0       -32768  2004189184      20922789888000          20922789888000
              0       32768   2004189184      20922789888000          20922789888000
      Enter a number > 0, or 0 to quit :17
      17!     0       -32768  -288522240      355687428096000         355687428096000
              0       32768   4006445056      355687428096000         355687428096000
      Enter a number > 0, or 0 to quit :18
      18!     0       0       -898433024      6402373705728000        6402373705728000
              0       0       3396534272      6402373705728000        6402373705728000
      Enter a number > 0, or 0 to quit :19
      19!     0       0       109641728       121645100408832000      121645100408832000
              0       0       109641728       121645100408832000      121645100408832000
      Enter a number > 0, or 0 to quit :20
      20!     0       0       -2102132736     2432902008176640000     2432902008176640000
              0       0       2192834560      2432902008176640000     2432902008176640000
      Enter a number > 0, or 0 to quit :21
      21!     0       0       -1195114496     -4249290049419214848    -4249290049419214848
              0       0       3099852800      14197454024290336768    14197454024290336768
              
      Enter a number > 0, or 0 to quit :32
      32!     0       0       -2147483648     -6045878379276664832    -6045878379276664832
              0       0       2147483648      12400865694432886784    12400865694432886784
      Enter a number > 0, or 0 to quit :33
      33!     0       0       -2147483648     3400198294675128320     3400198294675128320
              0       0       2147483648      3400198294675128320     3400198294675128320
      Enter a number > 0, or 0 to quit :34
      34!     0       0       0               4926277576697053184     4926277576697053184
              0       0       0               4926277576697053184     4926277576697053184
              
      Enter a number > 0, or 0 to quit :64
      64!     0       0       0               -9223372036854775808    -9223372036854775808
              0       0       0                9223372036854775808     9223372036854775808
      Enter a number > 0, or 0 to quit :65
      65!     0       0       0               -9223372036854775808    -9223372036854775808
              0       0       0                9223372036854775808     9223372036854775808
      Enter a number > 0, or 0 to quit :66
      66!     0       0       0               0                       0
              0       0       0               0                       0
      
      
      Typically, the result gets smaller or negative as the factorial increases beyond when the precision gets insufficient to hold the full result.  The int type at 16! is an exception.  From the results above it can be seen that a long int and a long long int are the same on this system.  Every multiplication by a number divisible by two adds a zero to the right side of the binary number.  Thus after sufficient zeros are added the number becomes zero.  Note that one odd number multiplication of the number before becoming zero does not change the result. The modified C code with different precision factorial computations.
       #include <stdio.h>  
       /* Program for computing the factorial of a number */  
       int main(int nvar, char** vars) {  
        int n,i;  
        char ck;  
        short sk;  
        int ik;  
        long int lk;  
        long long int llk;  
        unsigned char uck;  
        unsigned short usk;  
        unsigned int uik;  
        unsigned long int ulk;  
        unsigned long long int ullk;
        
        printf("Bytes\t%d\t%d\t%d\t%d\t%d\n",sizeof(ck),sizeof(sk),sizeof(ik),sizeof(lk),sizeof(llk));  
        while( 1 ) {  
         printf("Enter a number > 0, or 0 to quit :");  
         scanf("%d",&n);  
         if( n < 1 ) break;  
         ck = sk = ik = lk = llk = uck = usk = uik = ulk = ullk = 1;  
         for(i=1;i<=n;i++) {  
          ck *= i;  
          sk *= i;  
          ik *= i;  
          lk *= i;  
          llk *= i;  
          uck *= i;  
          usk *= i;  
          uik *= i;  
          ulk *= i;  
          ullk *= i;  
         }  
         printf("%d!\t%hhi\t%hi\t%i\t%li\t%lli\n",n,ck,sk,ik,lk,llk);  
         printf("\t%hhu\t%hu\t%u\t%lu\t%llu\n",uck,usk,uik,ulk,ullk);  
        }  
       }  
      
      The spreadsheets and R use double precision floating point numbers by default. These behave differently than integer types for large numbers. Also, I did a test with different spreadsheets and R with 70! I used LibraOffice, Calligra and Gnumeric with 70! to compare accuracies. Each spreadsheet gave the same answer with the fact() function as programming the cells. When the cell is made wide enough an integer is shown. LibraOffice shows 15 significant digits followed by zeros while Calligra Sheets and Gnumeric show digits to fill the integer. The 13th through 18th digits of 70! for different spreadsheets are
      • 699000 - LibraOffice
      • 698922 - Calligra Sheets
      • 698903 - Gnumeric
      • 698918 - Exact 70!
      Where it can be seen that Calligra Sheets is very slightly more accurate than the other spreadsheets. To 22 places R gives the same answer as Calligra Sheets.

      No comments:

      Post a Comment