If you are not familiar with factorial read this.
Question: Find the last non-zero digit of n!
Approach 1
If you think you can calculate the factorial first and then divide out all the zeroes, you can but only to a certain extent, i mean to the point you can calculate n factorial. What if you had to find the last non-zero digit of a very large number whose factorial you cannot calculate.
Approach 2
This is the most popular technique and quite handy too. We know that n! = 1 x 2 x 3 …x (n-1) x n
or n! = (2^a2)(3^a3)(5^a5)(7^a7)…
or n! = (2^a2)(5^a5)(3^a3)(7^a7)…
Now we know that the number of zeroes in n1 is equal to a5. So n! divided by 10^a5 will be equal to factorial without trailing digits. Lets call this n! without trailing zeroes as (n!)’ .So,
(n!)’ = (2^(a2-a5))(3^a3)(7^a7)…
Let L(k) denote the least significant non-zero decimal digit of the integer k. So from above we can infer that
L(n!) = L((n!)’) = L[(2^(a2-a5))(3^a3)(7^a7)...]
= L[(3^a3)(7^a7)...]*L[(2^(a2-a5))]
This logic is implemented in the C/C++ function below.
int last_digit_factorial(int N)
{
int i,j,ans=1,a2=0,a5=0,a;
for (i = 1; i <= N; i++)
{
j = i;
//divide i by 2 and 5
while (j%2==0)
{
j /= 2;
a2++;
}
while (j%5==0)
{
j/=5;
a5++;
}
ans = (ans*(j%10))%10;
}
a=a2-a5;
for (i = 1; i <= a; i++)
ans=(ans * 2) %10;
return ans;
}
Approach 3
Fact :The powers of 2 3 7 and 1 have cyclic last digit.
So we divide all the primes into one of these groups and then take out the power accordingly.
power1[4]={1, 1, 1, 1}
power2[4]={6, 2, 4, 8}
power3[4]={1, 3, 9, 7}
power7[4]={1, 7, 9, 3}
power9[4]={1, 9, 1, 9}
So for example, if we have to find last digit in 6!
6! = 1 * 2 * 3 * 4 * 5 * 6
6! = 2^3 * (3^2) * 10
6!’ = 2^3 * (3^2)
We know the power of 3 has cyclic last digit, so 3^2 last digit is 9 or power3[2 mod 4]
L(6!) = L(6!’) = power2[3 mod 4] * power3[2 mod 4] mod 10
= 32 mod 10 = 2
But why code this method when we have a simpler approach.
Approach 4
Theory : Since we know that only a factor 5 brings in zero and we always have more powers of 2 than of 5, so the value of L(n!) is easily computed recursively as L(L(n)L((n-1)!)) unless n is a multiple of 5, in which case we need more information. As a result, the values of L(n!) come in fixed strings of five, as shown below :
| 1 | 5 | 10 | 15 | 20 | 25 | |
| L(n!) | 1264 | 22428 | 88682 | 88682 | 44846 | 44846 |
Thus if we know any value of 5n we can get the value of 5n+j. For example if we know value of L(15!) we know the value of L(16!), L(17!) up-to L(19!). But how to get the value of 5n. If we map the starting values of the L(5n!) we get like 2 8 8 4 4 8 2 2 6. They come in another fixed strings of five. So we need to know L(25n!) to know L((25n+5j)!) for j = 0,1,2,3,4. Continuing in this way if we tabulate the values of L((5^t n)!) we get :
| L(n!) | 1264 | 22428 | 88682 | 88682 | 44846 | 44846 |
| L(5n!) | 2884 | 48226 | 24668 | 48226 | 48226 | 86442 |
| L(25n!) | 4244 | 82622 | 82622 | 28488 | 46866 | 64244 |
| L(125n!) | 8824 | 68824 | 26648 | 68824 | 42286 | 26648 |
| L(625n!) | 1264 | 22428 | 88682 | 88682 | 44846 | 44846 |
So we see that the pattern for L(625n!) is same as L(n!). Hence we can conclude that the pattern for L((5^j n)!) is the same as for L((5^(j+4) n)!). So we can use a modulo 4 function to get the next results. Also we can see below that each of the four row have a starting digit as 0 , 2 , 4, 6 and 8.
Result :
| k mod 4 | |||||
| 0 | 06264 | 22428 | 44846 | 66264 | 88682 |
| 1 | 02884 | 24668 | 48226 | 62884 | 86442 |
| 2 | 04244 | 28488 | 46866 | 64244 | 82622 |
| 3 | 08824 | 26648 | 42286 | 68824 | 84462 |
This is all we need to get the last digit of n! or L(n!). First we convert the given number n into base 5. So we have
n = d_0 + d_1*5 + d_2*5^2 + … + d_h*5^h
where d_0 is the least significant digit.
Now we enter the above table at the row h (mod 4) in the block whose first digit is 0 (because the coefficient of 5^(h+1) is zero), and determine the digit in the (d_h)th position of this block. Let this digit be denoted by s_h. Then we enter the table at row h-1 (mod 4) in the block that begins with s_h, and determine the digit in the (d_(h-1))th position of this block. Let this digit be denote by s_(h-1). We continue in this way down to s_0, which is the least significant non-zero digit of n!.
Example :
To illustrate, consider the case of the decimal number n=1592. In the base 5 this is n=22332. Now we enter the above table at row k=4=0 (mod 4) in the block beginning with 0, which is 06264. The leading digit of n (in the base 5) is 2, so we check the digit in position 2 of this block to give L((2*5^4)!) = 2. Then we enter the table at row k=3 (mod 4) in the block beginning with 2, which is 26648, to find L((2*5^4 + 2*5^3)!) = 6.
Then in the row k=2 (mod 4), the block beginning with 6 is 64244, and we find L((2*5^4 + 2*5^3 + 3*5^2)!) = 4. From this we know we’re in the block 48226 in row k=1 (mod 4), so we have L((2*5^4 + 2*5^3 + 3*5^2 + 3*5)!) = 2. Finally, we enter the row k=0 (mod 4) in block 22428 to find the result
L(1592!) = L((2*5^4 + 2*5^3 + 3*5^2 + 3*5 + 2)!) = 4
Thus if there are k digits in the base 5 representation of n then we only need k lookups in the table to get the last non-zero digit. Finally a C++ program for the algorithm :
#include<iostream>
using namespace std;
int A[4][5][5] = {
{0,6,2,6,4,2,2,4,2,8,4,4,8,4,6,6,6,2,6,4,8,8,6,8,2},
{0,2,8,8,4,2,4,6,6,8,4,8,2,2,6,6,2,8,8,4,8,6,4,4,2},
{0,4,2,4,4,2,8,4,8,8,4,6,8,6,6,6,4,2,4,4,8,2,6,2,2},
{0,8,8,2,4,2,6,6,4,8,4,2,2,8,6,6,8,8,2,4,8,4,4,6,2}
};
char num[200];
char* dto5(int n)
{
int b=5;
int j,l;
register int i=0;
do
{
j=n%b;
num[i++]=(j<10) ? (j+'0'): ('A'+j-10);
}while((n/=b)!=0);
num[i]='';
l=strlen(num);
reverse(num,num+l);
return num;
}
int last_digit_factorial(int N)
{
char *num=dto5(N);
int l = strlen(num),s=0,i;
for (i=0;i<l;i++)
{
s=A[(l-1-i)%4][s/2][num[i]-'0'];
}
return s;
}
int main()
{
int N;
while (scanf("%d", &N) == 1)
{
printf("%d\n", last_digit_factorial(N));
}
return 0;
}
You can change the above code to handle string if the input number is very large.
NJOY!!!
fR0D
June 28, 2009 at 3:32 PM |
I found the post very useful. . .
Thanks a lot. . .
Hope that a lot of such important posts will be come on later:-). . .
September 26, 2009 at 2:58 PM |
how about finding last k nonzero digits of factorial??