Last non-zero digits of a very large factorial
Asked Answered
C

1

5

How can one calculate the last few non-zero digits of a factorial of a large number?

By large, i mean like n=10^100 or something
(EDIT : 10^100 is the magnitude of 'n' in n! )
By few, i mean till 7-8...

I tried googling it and found this -

Last non-zero digit of a factorial

I tried to expand this to last 2 non-zero digits or more, but failed...

I found other websites on google that showed how to calculate last x number of digits but it wasn't clear and i wasn't able to understand it...

Can anyone help me with this?

Also, am not able to get this, the last two non-zero digits of 99! are 64, so i figured that the last two non-zero digits of (199! / 99!) should also be 64, but they turn out to be 24, i know i am making an extremely big logical mistake in this one, am just not able to put my finger on it!

Chit answered 20/7, 2017 at 19:52 Comment(21)
Just do the math on the last n digits throwing everything else. Use modSchaefer
@JeremyKahan: What's your estimate on how long it would take to compute factorial(10**100)?Shop
@JeremyKahan Clearly, either you have NO idea about how to solve the question and the complexities that come with your solution, or i am not able to understand what you meanChit
@JeremyKahan "Also when you multiply by 102 the last two digits change. So no reason to assume those factorial end the same " Sir, with all due respect, please read the whole question once again, THINK about it, and then only comment...Chit
Just to clarify: Is 10^100 the magnitude of the result of the factorial, or of the input?Womanize
@HarshitSinghal With all due respect, I suggest you not turning off people who are trying to help you. Sometimes, a seeming very complex problem can have a very simple solution that is just not apparent to the asker. Not saying that this is necessarily the case here, but it might. Better have a comment that's not very helpful than to prevent a helpful comment from being made.Womanize
@Womanize 10^100 is the magnitude of the input...Chit
@Womanize Yeah i know, i got a little carried away there i guess...Chit
@JamesKPolk I assume you mean the last digits of thatSchaefer
I see what you mean. All right then.Schaefer
Sorry li did not see the /Schaefer
@JeremyKahan Multiplying or dividing by 100 wont make a difference in the non-zero digits buddy...So 199! / 99! and 199! / 100! would be the same...Chit
Computing this without a pretty significant mathematical trick is essentially out of the question. I suggest you find the mathematical trick first and then worry about programming it. Recommending migration to Mathematics SE.Hexose
I'm voting to close this question as off-topic because it belongs on math.stackexchange.comHexose
@Patrick87: actually, it can be done with a simple algorithm, no serious math trick is needed. But I agree, it is more of a math.stackexchange.com question.Sway
@HarshitSinghal I saw that a couple of minutes later and withdrew it. I really did not mean to get you upset. I was distracted, and I should not have been posting in that frame of mind.Schaefer
@JeremyKahan no problem man...its all good...Chit
See oeis.org/A008904 and references therein for the single last non-zero digit. Try to implement and run the various formulas given, try to understand how and why they work, then try to see whether any of them generalizes to more digits, or to a different number base.Ramberg
My opinion is that Mathematics SE will think of it as a programming problem, this site will think of it as a math program. You need someone on the boundary who can look at it both ways. Both in terms of the math tricks AND the programming tricks that are needed. (I may be biased. I answered the question.)Mcdavid
Here is something potentially useful about why the two examples in the question differ in their last 2 digits. Our intuition that only the last 2 digits matter seems to get thrown off when a 0 gets tacked on ta the end. For instance, suppose your last piece until now ended in 22. If you multiply by 25 or 125 you get different last 2 nonzero digits because the 1 ends up mattering.Schaefer
@JeremyKahan Differences arise in two places. One is at 25 versus 125, the extra factor of 5 adds a digit and divides the non-zero part by 2. The other place is spots like 120 versus 20. The leading 2 digits got multiplied by different things.Mcdavid
M
10

The trick to do your calculations is that you want to find 3 numbers.

  1. The number of factors of 5 in the answer.
  2. The number of factors of 2 in the answer.
  3. The last few digits of all of the products of all of the other primes in the answer.

The number of factors of 5 give you the number of factors of 10. Then subtract the number of factors of 2 from the number of factors of 5. Figure out the last few digits of 2 to that power. Multiply that by the last few digits found in step 3, and you're done.

The number of factors of 5 can be worked out as follows. Take n/5 (round down). That's how many have a first factor of 5. Then n/25 (round down). That how many have a second factor of 5. Continue until you're done.

The number of factors of 2 can be worked out similarly only with the sequence 2, 4, 8, 16 instead.

The third part is tricky.

But what is easier is to do is figure out the product of all of the numbers up to and including n which are relatively prime to 2 and 5. Call that function f(n). You can calculating it by multiplying the relatively prime numbers mod 10^k. And take advantage of the fact that f(i * 10^k + j) = f(j) mod(10^k).

Then you want the last few digits of f(n)*f(n/2)*f(n/4)*f(n/5)*f(n/8)*f(n/10)*f(n/16)*.... Producing that sequence efficiently is a version of the Hamming Numbers problem. See https://rosettacode.org/wiki/Hamming_numbers for how to do that. For 10^100 there will still only be tens of thousands in this sequence - it is well under control.


For your second question about ratios, you'll need to take advantage of the following two facts. Fact 1 is that you know the right number of factors of 2 and 5 just through subtraction. The second is that if m is relatively prime to 10 then m * m^(4 * 10^(k-1) - 1) is 1 mod 10^k. So you can now "divide" mod 10^k, and figure out the last few terms of every factor of the answer that doesn't involve a 2 or a 5, then figure out the number of 0s, and the number of leftover factors of 2 or 5 that you have.


Here is a significant optimization. If you know f(n) mod 2^8 and 5^8, it isn't hard to figure it out mod 10^8. But its value mod those two can be reduced to a lookup table of modest size. The larger one you only need to store it for odd n up to 4*390625, but there are less than 800k of those. (At that point you've multiplied by all elements of the group of things not divisible by 5 mod 5^8, and that product is 1. Then the pattern repeats.) If you're using 4 byte integers, that's few MB lookup table that can be precalculated fairly easily.

I should probably explain why this trick works, because it isn't obvious and I got it wrong a couple of times. The trick is that the numbers relatively prime to 5^k form a group. Meaning each has an inverse. So if you multiply them all out, and rearrange, each has an inverse EXCEPT 5^k-1. So multiply by another copy and they pair up again including that pesky one and the product comes out to 1. Now for our f we are only interested in odd numbers not divisible by 5, but the odd ones not divisible by 5 out to 2*5^k are, mod 5^k, just a rearrangement of the ones divisible by 5 out to 5^k. We need 2 copies, hence out to 4*5^k. But we only need the odds because the even right after always has the same value as the previous odd.


Per request, here is how this works for a single example. I'll do the last 3 digits of 15!

15! = 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15
    = (1*3*7*9*11*13) * (2*6*14) * (4*12) * (5*15) * (8) * (10)
    = (1*3*7*9*11*13) * 2^3*(1*3*7) * 2^4*(1*3) * 5^2*(1*3) * 2^3*(1) * 10*(1)
    = 2^11 * 5^3 * f(15) * f(15/2) * f(15/4) * f(15/5) * f(15/8) * f(15/10)
    = 2^11 * 5^3 * f(15) * f(15/2) * f(15/4) * f(15/5) * f(15/8) * f(15/10)
    = 10^3 * 2^8 * f(15) * f(7) * f(3) * f(3) * f(1) * f(1)
    Which leads to the calculation...
             256 *   27  *  21  *   3  *   3  *   1  *   1 (mod 1000)
                                                     = 368 (mod 1000)

This is correct because 15! = 1307674368000.

Mcdavid answered 20/7, 2017 at 21:57 Comment(18)
Is it a theorem behind f(n)*f(n/2)..., or is it trivial to see? What if n is not divisible by 2? What does f(n/2) contain then?Sway
@Sway It is trivial. n! = 1*2*3*...*n. Define q(n) to be the largest integer <= n which is not divisible by 2 or 5. Sort the terms from smallest to largest, first by the largest factor made out of 2s and 5s, then by whatever the remaining factor is. Pull the factors of 2 and 5 out. You'll now have the form 5^big * 2^bigger * (1*3*7*9*...*q(n))*(1*3*7*9*...*q(n/2)) * (1*3*7*9*...*q(n/4)) * (1*3*7*9*...*q(n/5)) * ... Which is 5^big * 2^bigger * f(n) * f(n/2) * f(n/4) * f(n/5) * ....Mcdavid
@Sway So we're rounding down those divisions. If n is odd, then f(n/2) = f((n-1)/2).Mcdavid
Thanks! I'll try to understand you tomorrow, it's too late here now :) Anyways, that's why I think this is more of a math problem, than a programming one.Sway
@Sway And conversely, "Here is how you represent these numbers", "Here is how you store them", "Here is what is doable in a lookup table" - these are all questions that a program needs to address that the math people would consider to be more of a programming problem. Indeed this one would make an excellent hard Project Euler problem. (See projecteuler.net/problem=160 for a medium problem of this form.)Mcdavid
To be honest, first I thought that it is actually a PE problem :) But I think their actual problems are much harder than this. This problem could have been around ~200. Maybe you can try to send them this problem, and they can make it harder. Yes, I see what you mean... for programmers, this is more of a math problem, for mathematicians, this is more of a programming problem.Sway
My solution is this: create a loop, factor=1->10^k. Calculate, how many times (call it t) a factor with k-digit ending exists (it is about n/10^k). Then calculate modpow(factor, t), and modulo-multiply this to the result. Of course, factors 2 and 5 should be handled like in your solution. I hope you understand the outline :)Sway
@Sway That's clever but you'll need some fancy footwork with how to handle factors of 2 you pull out of ...xy2, how many more you pull out of ...xy4, and what sequence of numbers you'll have left in the ...5 list of factors once you pull all of the factors of 5 out of there as well. The analysis will be tricky and you had better get your counts right.Mcdavid
I think this answer could be improved with an example. Can you show how it produces, e.g., the last 1 digit of 11! ?Hexose
@Hexose I added how it produces the last 3 digits of 15! - in a way that shows why the calculation works.Mcdavid
@Mcdavid Thanks for such a nice and well explained answer...and yeah, that example helps loads! I'll try to understand the concept and make a program out of it...Lets hope i do it right!Chit
@Mcdavid i was successful in implementing the algorithm...but i had to calculate the last 7 digits which came out to be 3629056...then i had to do some other shit with this number too, but after doing that, answer came out to be wrong...i tried going for last 8 digits thinking i might need to remove that '0' in the middle, but got too a "MemoryError" while saving the values of f(n)...i guess I'll talk to the problem setter and ask for some guidance on where i am going wrong...Thanks alot for you answer though...helped a lot...Chit
The statement f(i * 10^k + j) = f(j) mod(10^k) is incorrect, where I interpret k as the number of non-zero digits seeked. For instance f(3) and f(13) end with a different digit (k=1).Intrauterine
@Intrauterine Check that. f(3) = 1 * 3 = 3 and f(13) = 1 * 3 * 7 * 11 * 13 = 3003. They end with the same digit, namely 3.Mcdavid
Thanks for the reply. Isn't f(13) = 1 * 3 * 7 * 9 * 11 * 13 = 27027 ? This is consistent with how you computed f(15) above. And more generally it should be this sequence: oeis.org/A232984Intrauterine
@Intrauterine Oops. It has been a few years, but check the paragraph starting with "I should probably explain why this trick works, because it isn't obvious and I got it wrong a couple of times." Keep reading through the explanation why, mod 5^k, 4*5^k odds give you a 1. Which means that if 2 <= k, then that relation is correct, but for k = 1 it is not. (Because there is an unpaired -1 mod 5^k` = which is here the 9.)Mcdavid
At the time I wrote this I had working code that demonstrated it, but didn't post because I thought it was for a competition. But maybe I'll get inspired and write working code.Mcdavid
I see, this clarifies it, thanks. I checked for larger numbers and it looks fine.Intrauterine

© 2022 - 2024 — McMap. All rights reserved.