views:

2138

answers:

18

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

+3  A: 

Rewrite the recursive solution as a loop.

JohnMcG
Doh! Of course.. a loop :-B
OscarRyz
+3  A: 
public double factorial(int n) {
    double result = 1;
    for(double i = 2; i<=n; ++i) {
        result *= i;
    }
    return result;
}
Chris Marasti-Georg
I think you need <=. factorial(3) returns 2.
MrDatabase
should be for(int i = 2; i<= n; ++i)
matt b
Homework questions are allowed. There was a post earlier today about that. However, the code that is posted in response should be given a pseudo-code.
Elie
thanks guys - trying to be quick :/
Chris Marasti-Georg
+2  A: 
long fact(int n) {
    long x = 1;
    for(int i = 1; i <= n; i++) {
        x *= i;
    }
    return x;
}
Bill the Lizard
A: 
int fact(int n){
    int r = 1;
    for(int i = 1; i <= n; i++) r *= i;
    return r;
}
MrDatabase
for (i=n; i; i--) r *= i;
PhirePhly
A: 

Pseudo code

total = 1
For i = 1 To n
    total *= i
Next
EBGreen
A: 
fac = 1 ; 
for( i = 1 ; i <= n ; i++){
   fac = fac * i ;
}
stephanea
+1  A: 
int total = 1
loop while n > 1
    total = total * n
    n--
end while
Elie
+13  A: 

in pseudocode

ans = 1
for i = n down to 2
  ans = ans * i
next
Vincent Ramdhanie
A: 
public int factorialNonRecurse(int n) {
    int product = 1;

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

    return product;
}
matt b
Does not compile
Chris Marasti-Georg
+5  A: 

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 Ramponi
+15  A: 

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
A O(1) algorithm is a good idea. But I don't think 1! == 2.
Jeffrey L Whitledge
fixed. Damn zero index!!
BradC
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
Also, the second to last number should be 39916800, not 3991800 (this may illustrate a problem with look up tables).
Wedge
make the array static
EvilTeach
Not in e.g. Ruby, where it automatically switches to a big integer representation.
martinus
@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
A: 

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
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
(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
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
+3  A: 

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
+3  A: 

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
Perhaps more of an endictment of C# and .Net ;)
Richard A
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
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
A: 

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
You might be thinking of the fibonacci sequence - factorial does not benefit from memoization.
Kyle Cronin
A: 

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; }

A: 

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 struct Factorial { enum { value = N * Factorial::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 }

+1  A: 

I love the pythonic solution to this:

def fact(n): return (reduce(lambda x, y: x * y, xrange(1, n+1)))
dangerouslyfacetious