The code here only gives correct output till the factorial of 21 and after that its correct upto 16 digits from the left then remaining digits are just given as zero. I tried changing the type of variable c
from double
to long double
but it just gives errors or doesn't print the factorials.
#include <stdio.h>
FILE *fp;
long double facto(int i);
int main() {
int n, i;
double c;
printf("enter no. to find factorial till:\n");
scanf("%d", &n);
fp = fopen("output_of_factorial.txt", "w");
fputs("Number |\t Factorial\n\n", fp);
for (i = 1; i <= n; i++) {
c = facto(i);
fprintf(fp, "%d\t|\t %.0Lf\n", i, c);
}
fclose(fp);
return 0;
}
long double facto(int x) {
if (x == 1)
return 1;
else
return x * facto(x - 1);
}
Tye double
only has 53 bits of precision, long double
probably has 80 bits on your platform. Using floating point arithmetics will give you an approximate result that is correct for the most significant digits. Using integers give you the exact result, but only if it is smaller than the range of the type.
You can use the type long long
that is at least 64-bit wide, thus 19 digits, or for one more bit, type unsigned long long
that allows for integers twice as large:
LLONG_MAX = 9223372036854775807 // > 9.22e19
ULLONG_MAX = 18446744073709551615 // > 1.84e20
Here is a modified version of the code:
#include <stdio.h>
unsigned long long facto(int i);
int main(void) {
int n, i;
unsigned long long c;
FILE *fp;
printf("enter no. to find factorial till: ");
if (scanf("%d", &n) == 1) {
fp = fopen("output_of_factorial.txt", "w");
if (fp != NULL) {
fputs("Number | Factorial\n\n", fp);
for (i = 1; i <= n; i++) {
c = facto(i);
fprintf(fp, "%6d | %20llu\n", i, c);
}
fclose(fp);
}
}
return 0;
}
unsigned long long facto(int x) {
if (x <= 1)
return 1;
else
return x * facto(x - 1);
}
It works all the way to 20
:
Number | Factorial
1 | 1
2 | 2
3 | 6
4 | 24
5 | 120
6 | 720
7 | 5040
8 | 40320
9 | 362880
10 | 3628800
11 | 39916800
12 | 479001600
13 | 6227020800
14 | 87178291200
15 | 1307674368000
16 | 20922789888000
17 | 355687428096000
18 | 6402373705728000
19 | 121645100408832000
20 | 2432902008176640000
But fails for 21 and above because of arithmetic overflow.
To go further, you could use 128-bit integers if they are available on your platform (uint128_t
, __uint128
or __uint128_t
) but you would need to write your own conversion function to output the decimal representation.
A better approach would be to use multi-precision (aka bignum) packages that can handle extremely large numbers, typically only bound by available memory.