Tuesday, June 3, 2025

Factorials

 Let me return now to the basics of recursion to bring up another simple, classic problem: the calculation of the factorial. You may have heard some urban legend about Gauss, who was in class, and someone misbehaved, so the teacher said “You can’t go to recess until you find the sum of 1+2+3+…+100,” thinking this would keep the students busy a long while.


Gauss, the legendary mathematician he was, found the answer in seconds: 1+100 is a pari that sums to 101; and so is 2+99; and so is 3+98; and so is 4+97; and so on. We’re going from 1 to 100, so we have 100/2 = 50 pairs. The sum of the pair is 101, and we have 50 pairs, so the sum of 1+2+3+…+100 is 50*101 = 5050. (And indeed this generalizes for any upper bound: for some bound n, the sum ofthe first n numbers is n*(n+1)/2.)

That sequence grows quickly—1, 3, 6, 10, 15, 21, 28, and so on. But we are after a sequence that grows much, much more quickly.

In fact, let’s call the additive version of 1[operator]2[operator]3[operator]4… Gauss(n). Now let’s look at what happens when the operation is not addition, but multiplication: 1, 2, 6, 4, 120, 720, … etc. For now, let’s call this Mystery(n). It has a proper name and a real definition, but let’s just keep it vague for now as we appreciate how insanely quickly this number is growing.

 I claim—and by the end of this article, you’ll be able to prove me right—that Gauss(10) is 55, but Mystery(10) is more than 3 million; Gauss(20) is 210, but Mystery(20) is 2.4 billion billion. Put another way, Mystery() grows much, much faster than Gauss(). No, that isn’t a typo: Mystery(20) is somewhere in the ballpark of 2,400,000,000,000,000,000.  You can count to Gauss(20) in about 3 and a half minutes, at one number per second. You would need about 6 times the age of the universe to count to Mystery(20) at one number per second.

Mystery(), in fact, is the factorial function—what you get when you replace every + in the Gauss sequence with a *.

Imagine you’re a teacher, and you want to line up your students. You have Alice, Bob, and Charlie in your class. How many ways are there to arrange them?

Alice can come first. Then either Bob or Charlie. Then whoever wasn’t second must come third.

Bob can come first. Alice or Charlie can follow. Whoever wasn’t picked completes the triple.

Charlie can lead. Alice or Bob can be next. Whoever is left necessarily must come here.

Expressed as a set, we have ABC, ACB, BAC, BCA, CAB, CBA: six choices.

Now, let’s remove Charlie. {Alice, Bob} is possible; and so is {Bob, Alice}.

Now, let’s remove Bob. {Alice} is the only ordering.

Now, let’s do something strange: remove Alice. {} is the only ordering.


We can express this function in one of two ways: in a loop, like what the students might have done if the punishment problem had been to multiply: 1*2, 1*2*3, 1*2*3*4, and so on…

and the pseudocode looks like:

FUNCTION factorial(n)

    result ← 1

    FOR i FROM 2 TO n

        result ← result * i

    END FOR

    RETURN result

END FUNCTION

This correctly computes the value, but there’s a better, more classic, more elegant way.

Notice that 6! (“six factorial,” not “SIX!!!!!!!!”) is 6 times 5!; 5! Is 5 * 4!; and so on.

This allows us to very neatly, recursively define factorial().

 

Recall from our student-ordering experiment that, after we get rid of Alice, there is still one way to put no students in order: {}. Do nothing. That actually matters here because it gives us a defined value at 0.

Factorials are used to count the number of ways to arrange some number of objects, so, naturally, there is one way to arrange 0 objects: do nothing. That is one intuitive way to get to the fact that 0! Is 1, but we’ll see another by the end of this article.

To define something recursively, we need a base case—we have it, that 0!=1—and a rule, that the factorial of some number is the factorial of the previous number, times the number (5! = 5 * 4!; 100!  = 100 * 99!; and so on).

Armed with these two pieces of information, we can arrive at the following recursive definition:

FUNCTION factorial(n)

    IF n = 0 OR n = 1 THEN

        RETURN 1

    ELSE

        RETURN n × factorial(n - 1)

    END IF

END FUNCTION


The other way to get to the fact that 0! Is 1 is the following:

·       10! is 3628800

·       9!  Is 10!/10, or 362880

·       8! Is 9!/9, or 40320

·       7! Is 8!/8, or 5040

·       6! Is 7!/7, or 720

·       5! Is 6!/6, or 120

·       4! Is 5!/5, or 24

·       3! Is 4!/4, or 6

·       2! Is 3!/3, or 2

·       1! Is 2!/2, or 1—and up to this point, there should be no argument, since I am just applying the pattern that n! = n * (n-1)! In reverse

·       So naturally, 0! Is 1!/1, which is 1.

No comments:

Post a Comment

Switch

 Other than if/if-else/if-else if-else and the ternary operator, there is yet another common and important conditional expression in Java th...