views:

670

answers:

9

Hi all, I understand this is a classic programming problem and therefore I want to be clear I'm not looking for code as a solution, but would appreciate a push in the right direction. I'm learning C++ and as part of the learning process I'm attempting some programming problems. I'm attempting to write a program which deals with numbers up to factorial of 1billion. Obviously these are going to be enormous numbers and way too big to be dealing with using normal arithmetic operations. Any indication as to what direction I should go in trying to solve this type of problem would be appreciated.

I'd rather try to solve this without using additional libraries if possible

Thanks

PS - the problem is here http://www.codechef.com/problems/FCTRL


Here's the method I used to solve the problem, this was achieved by reading the comments below:

Solution -- The number 5 is a prime factor of any number ending in zero. Therefore, dividing the factorial number by 5, recursively, and adding the quotients, you get the number of trailing zeros in the factorial result

E.G. - Number of trailing zeros in 126! = 31

126/5 = 25 remainder 1

25/5 = 5 remainder 0

5/5 = 1 remainder 0

25 + 5 + 1 = 31

This works for any value, just keep dividing until the quotient is less than 5

+1  A: 

As you'll find in other answers, you need a Big Integer library. A very popular implementation is GNU's MP.

Concerning the real problem, I think there's a simple mathematical way to find the answer without actually calculating the factorial.

GMan
Thanks, but is there a way to do this without a big int library? I'm not looking to reinvent the wheel but rather try to use a more interesting method if it's possible. For example, I was thinking that I may be able to use logs or even multidimensional arrays, not quite sure just yet. Hence the question.
Griffo
No, you need a bignum library without reinventing a bignum library (or reinventing the concept of a bignum library that is)
Earlz
This is not a problem even for a bignum library. This is a problem for a very clever algorithm which outputs the binary digits in order from least- to most-significant without otherwise explicitly representing the solution.
Potatoswatter
@Potato: Hence my second clause. My first clause answers his misguided question.
GMan
Put another way, factorial growth is faster that exponential growth. If you're calculating one billion factorial, the answer will be between 2^billion (1 gigabit, 128 MB) and billion^billion (30 gigabits, 3840 MB).
Potatoswatter
@GMan, sorry, I was talking to earlz.
Potatoswatter
@Potato, no problem. Put @earlz in your comment and he'll be notified of your response, by the way.
GMan
A: 

To start you off, you should store the number in some sort of array like a std::vector (a digit for each position in the array) and you need to find a certain algorithm that will calculate a factorial (maybe in some sort of specialized class). ;)

Partial
repeating another comment, factorial growth is faster that exponential growth. If you're calculating one billion factorial, the answer will be about half as long as a billion^billion (about 15 gigabits, 1920 MB). Multiply by two or three if you're keeping decimal digits in bytes.
Potatoswatter
A: 

You need a "big number" package - either one you use or one you write yourself.

I'd recommend doing some research into "large number algorithms". You'll want to implement the C++ equivalent of Java's BigDecimal.

Another way to look at it is using the gamma function. You don't need to multiply all those values to get the right answer.

duffymo
+3  A: 

Hint: you may not need to calculate N! in order to find the number of zeros at the end of N!

Chris Johnson
Thanks, that's a help then. Gets me thinking in a different way ;o)
Griffo
+1  A: 

This isn't a good answer to your question as you've modified it a bit from what I originally read. But I will leave it here anyway to demonstrate the impracticality of actually trying to do the calculations by main brute force.

One billion factorial is going to be out of reach of any bignum library. Such numbers will require more space to represent than almost anybody has in RAM. You are going to have to start paging the numbers in from storage as you work on them. There are ways to do this. The guy who recently calculated π out to 2700 billion places used such a library

Omnifarious
Yeah I forgot to state originally that I didn't want to use a bignum library. Thanks for the response anyway, it is certainly useful to understand the impracticality of a brute force method.
Griffo
+2  A: 

To solve this question, as Chris Johnson said you have to look at number of 0's.

The factors of 10 will be 1,2,5,10 itself. So, you can go through each of the numbers of N! and write them in terms of 2^x * 5^y * 10^z. Discard other factors of the numbers.

Now the answer will be greaterof(x,y)+z.

One interesting thing I learn from this question is, its always better to store factorial of a number in terms of prime factors for easy comparisons.

To actually x^y, there is an easy method used in RSA algorithm, which don't remember. I will try to update the post if I find one.

Algorist
Ah, great idea! Thanks, I'll give that some thought.
Griffo
You only need to deal with the prime factors (2 and 5). The easiest way I know of finding the exponents is dividing them out, e.g.`while(!(n%5)) {n/=5; y++;}`
Chris Johnson
I feel 10 should also be included because, it saves one extra check :-).
Algorist
The easy method used in the RSA algorithm that you are thinking of may rely on the fact that RSA always computes X^y in a mod field.
Omnifarious
Thanks Omnifarious. Yeah I remember now.
Algorist
So I guess I need to go revising my number theory. Could someone show an example of using 2^x * 5^y * 10^z on the factorial of a random number as described in this answer?
Griffo
+1  A: 

Do not use the naive method. If you need to calculate the factorial, use a fast algorithm: http://www.luschny.de/math/factorial/FastFactorialFunctions.htm

David Johnstone
+2  A: 

Skimmed this question, not sure if I really got it right but here's a deductive guess:

First question - how do you get a zero on the end of the number? By multiplying by 10.

How do you multiply by 10? either by multiplying by either a 10 or by 2 x 5...

So, for X! how many 10s and 2x5s do you have...?

(luckily 2 & 5 are prime numbers)

edit: Here's another hint - I don't think you need to do any multiplication. Let me know if you need another hint.

james
Haha, well that would be nice! I'm guessing that the answer lies in number theory?
Griffo
I don't think so (b/c I don't know what number theory is). Here's another hint...X! = 1 x2..x5..10..12..15..20..22..25..30.....X Those numbers will give you 6 zeros. How many zeros will X give you?
james
Thanks James, with your heavy prompting (lol) I solved it in 1.42 seconds! Well, three days, but the program solves it in 1.42 seconds. Thanks to everyone else who contributed!
Griffo
+1  A: 

I think that you should come up with a way to solve the problem in pseudo code before you begin to think about C++ or any other language for that matter. The nature of the question as some have pointed out is more of an algorithm problem than a C++ problem. Those who suggest searching for some obscure library are pointing you in the direction of a slippery slope, because learning to program is learning how to think, right? Find a good algorithm analysis text and it will serve you well. In our department we teach from the CLRS text.

gavaletz