18

How would you write a non-recursive algorithm to compute n!?

tshepang
  • 12,111
  • 21
  • 91
  • 136

22 Answers22

31

Since an Int32 is going to overflow on anything bigger than 12! anyway, just do:

public int factorial(int n) {
  int[] fact = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 
                362880, 3628800, 39916800, 479001600};
  return fact[n];
}
BradC
  • 39,306
  • 13
  • 73
  • 89
  • 8
    As written this would actually be slower, since initializing the array every call will be more expensive than ~12 multiplication operations (by about a factor of 2). A good look up table should use static data. Also, what happens when I pass 13 or -20 to this function? – Wedge Oct 23 '08 at 21:26
  • 3
    Also, the second to last number should be 39916800, not 3991800 (this may illustrate a problem with look up tables). – Wedge Oct 23 '08 at 23:10
  • Not in e.g. Ruby, where it automatically switches to a big integer representation. – martinus Jan 16 '09 at 22:16
  • 1
    @Wedge - my compiler says the lookup is faster by a factor of two (unless I pass in a constant into the function, in which case the compiler just returns a pre-calculated constant) – Eclipse Jan 26 '09 at 23:19
  • @Wedge from 2021 programmer to 2008 programmer, it get inlined as static data in the executable so the array doesn't need to be initialized – cdecompilador Aug 12 '21 at 11:13
19

in pseudocode

ans = 1
for i = n down to 2
  ans = ans * i
next
Vincent Ramdhanie
  • 102,349
  • 23
  • 137
  • 192
7
public double factorial(int n) {
    double result = 1;
    for(double i = 2; i<=n; ++i) {
        result *= i;
    }
    return result;
}
Chris Marasti-Georg
  • 34,091
  • 15
  • 92
  • 137
7

In the interests of science I ran some profiling on various implementations of algorithms to compute factorials. I created iterative, look up table, and recursive implementations of each in C# and C++. I limited the maximum input value to 12 or less, since 13! is greater than 2^32 (the maximum value capable of being held in a 32-bit int). Then, I ran each function 10 million times, cycling through the possible input values (i.e. incrementing i from 0 to 10 million, using i modulo 13 as the input parameter).

Here are the relative run-times for different implementations normalized to the iterative C++ figures:

            C++    C#
---------------------
Iterative   1.0   1.6
Lookup      .28   1.1
Recursive   2.4   2.6

And, for completeness, here are the relative run-times for implementations using 64-bit integers and allowing input values up to 20:

            C++    C#
---------------------
Iterative   1.0   2.9
Lookup      .16   .53
Recursive   1.9   3.9
Wedge
  • 19,513
  • 7
  • 48
  • 71
  • 1
    Perhaps more of an endictment of C# and .Net ;) – Richard A Oct 24 '08 at 01:10
  • So did you run these tests on a 64-bit CPU? If not, then I'm very curious about why half of the tests would be faster in the second test than the first. – Dave Sherohman Nov 18 '08 at 06:06
  • The figures in each table are normalized to the C++ iterative times for that table, the tables are not to scale with each other. Note that these runs were performed on a 32-bit OS and the 64-bit tests took longer than the 32-bit ones. – Wedge Nov 18 '08 at 17:02
5

Rewrite the recursive solution as a loop.

JohnMcG
  • 8,709
  • 6
  • 42
  • 49
5

Unless you have arbitrary-length integers like in Python, I would store the precomputed values of factorial() in an array of about 20 longs, and use the argument n as the index. The rate of growth of n! is rather high, and computing 20! or 21! you'll get an overflow anyway, even on 64-bit machines.

Federico A. Ramponi
  • 46,145
  • 29
  • 109
  • 133
3

Here's the precomputed function, except actually correct. As been said, 13! overflows, so there is no point in calculating such a small range of values. 64 bit is larger, but I would expect the range to still be rather reasonable.

int factorial(int i) {
    static int factorials[] = {1, 1, 2, 6, 24, 120, 720, 
            5040, 40320, 362880, 3628800, 39916800, 479001600};
    if (i<0 || i>12) {
        fprintf(stderr, "Factorial input out of range\n");
        exit(EXIT_FAILURE); // You could also return an error code here
    }
    return factorials[i];
} 

Source: http://ctips.pbwiki.com/Factorial

PhirePhly
  • 2,908
  • 1
  • 17
  • 12
2
long fact(int n) {
    long x = 1;
    for(int i = 1; i <= n; i++) {
        x *= i;
    }
    return x;
}
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
2
int total = 1
loop while n > 1
    total = total * n
    n--
end while
Elie
  • 13,693
  • 23
  • 74
  • 128
2

I love the pythonic solution to this:

def fact(n): return (reduce(lambda x, y: x * y, xrange(1, n+1)))
1
fac = 1 ; 
for( i = 1 ; i <= n ; i++){
   fac = fac * i ;
}
Graeme Perrow
  • 56,086
  • 21
  • 82
  • 121
stephanea
  • 1,108
  • 8
  • 10
1
public int factorialNonRecurse(int n) {
    int product = 1;

    for (int i = 2; i <= n; i++) {
        product *= i;
    }

    return product;
}
matt b
  • 138,234
  • 66
  • 282
  • 345
1

At run time this is non-recursive. At compile time it is recursive. Run-time performance should be O(1).

//Note: many compilers have an upper limit on the number of recursive templates allowed.

template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
1

For a non-recursive approach, it can't get simpler than this

int fac(int num) {
    int f = 1;
    for (int i = num; i > 0; i--)
        f *= i;
    return f;
}
Wael Assaf
  • 1,233
  • 14
  • 24
0

Iterative:

int answer = 1;
for (int i = 1; i <= n; i++){
    answer *= i;
}

Or... using tail recursion in Haskell:

factorial x =
    tailFact x 1
    where tailFact 0 a = a
        tailFact n a = tailFact (n - 1) (n * a)

What tail recursion does in this case is uses an accumulator to avoid piling on stack calls.

Reference: Tail Recursion in Haskell

nyanshak
  • 60
  • 6
0

Pseudo code

total = 1
For i = 1 To n
    total *= i
Next
EBGreen
  • 36,735
  • 12
  • 65
  • 85
0

assuming you wanted to be able to deal with some really huge numbers, I would code it as follows. This implementation would be for if you wanted a decent amount of speed for common cases (low numbers), but wanted to be able to handle some super hefty calculations. I would consider this the most complete answer in theory. In practice I doubt you would need to compute such large factorials for anything other than a homework problem

#define int MAX_PRECALCFACTORIAL = 13;

public double factorial(int n) {
  ASSERT(n>0);
  int[MAX_PRECALCFACTORIAL] fact = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 
                362880, 3628800, 39916800, 479001600};
  if(n < MAX_PRECALCFACTORIAL)
    return (double)fact[n];

  //else we are at least n big
  double total = (float)fact[MAX_PRECALCFACTORIAL-1]
  for(int i = MAX_PRECALCFACTORIAL; i <= n; i++)
  {
    total *= (double)i;  //cost of incrimenting a double often equal or more than casting
  }
  return total;

}
David Frenkel
  • 956
  • 7
  • 20
  • You have two off by one errors in your lookup section. Your check should be <= 12, and 1! does not equal 2. Also, you've copied the error above for 11!, it should be 39916800 not 3991800 (note the missing 6). Also, this needs error checking. What's factorial(-10)? or factorial(500)? – Wedge Oct 24 '08 at 00:31
  • (this is was aa lesson as to wy you should never jsut blindly copy your CS homework without testing it :) ) Corrected. Assert added, fixed the MAX value to include the new number (so <= not needed). Now this will work as a double version if it's needed for whatever reason. – David Frenkel Oct 24 '08 at 21:05
  • Excellent. You probably want to assert on too large input values as well though. With factorial you can quite easily overflow even a double. – Wedge Oct 24 '08 at 21:34
0

I would use memoization. That way you can write the method as a recursive call, and still get most of the benefits of a linear implementation.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
0
long fact(int n)
{
    long fact=1;
    while(n>1)
      fact*=n--;
    return fact;
}

long fact(int n)
{
   for(long fact=1;n>1;n--)
      fact*=n;
   return fact;
}
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
0

Non recursive factorial in Java. This solution is with custom iterator (to demonstrate iterator use :) ).

/** 
 * Non recursive factorial. Iterator version,
 */
package factiterator;

import java.math.BigInteger;
import java.util.Iterator;

public class FactIterator
{   
    public static void main(String[] args)
    {
        Iterable<BigInteger> fact = new Iterable<BigInteger>()
        {
            @Override
            public Iterator<BigInteger> iterator()
            {
                return new Iterator<BigInteger>()
                {
                    BigInteger     i = BigInteger.ONE;
                    BigInteger total = BigInteger.ONE;

                    @Override
                    public boolean hasNext()
                    {
                        return true;
                    }

                    @Override
                    public BigInteger next()
                    {                        
                        total = total.multiply(i);
                        i = i.add(BigInteger.ONE);
                        return total;
                    }

                    @Override
                    public void remove()
                    {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
        int i = 1;
        for (BigInteger f : fact)
        {
            System.out.format("%d! is %s%n", i++, f);
        }
    }
}
-1
int fact(int n){
    int r = 1;
    for(int i = 1; i <= n; i++) r *= i;
    return r;
}
MrDatabase
  • 43,245
  • 41
  • 111
  • 153
-2

Recursively using JavaScript with caching.

var fc = []
function factorial( n ) {
   return fc[ n ] || ( ( n - 1 && n != 0 ) && 
          ( fc[ n ] = n * factorial( n - 1 ) ) ) || 1;
}
Matt
  • 1
  • 1