Тая double
имеет только 53 бит точности, long double
, вероятно, имеет 80 бит на вашей платформе. Использование арифметики с плавающей точкой даст вам приблизительный результат, который будет правильным для наиболее значимых цифр. Использование целых чисел дает вам точный результат, но только если он меньше, чем диапазон типа.
Вы можете использовать тип long long
, который имеет ширину по меньшей мере, 64 бит, таким образом, 19 цифр, или для более одного бита, тип unsigned long long
, который позволяет для целых чисел в два раза больше:
LLONG_MAX = 9223372036854775807 // > 9.22e19
ULLONG_MAX = 18446744073709551615 // > 1.84e20
Вот модифицированный версия кода:
#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);
}
Он работает весь путь до 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
Но не работает 21 и выше из-за арифметического переполнения.
Чтобы идти дальше, вы могли бы использовать 128-битовые целые числа, если они доступны на вашей платформе (uint128_t
, __uint128
или __uint128_t
), но вам нужно будет написать свою собственную функцию преобразования для вывода десятичного представления.
Лучшим подходом было бы использование многоточечных (aka bignum) пакетов, которые могут обрабатывать чрезвычайно большие числа, как правило, только связанные доступной памятью.
Если вы переключаетесь с 'double' на' unsigned long long', вы можете получить до 20 цифр. Если вы используете gcc, вы можете использовать 128-битный тип '__uint128_t', который доставит вам до 40 цифр. Кроме того, вам понадобится библиотека с несколькими значениями. – njuffa
@njuffa: Хороший ответ, слишком плохо, что вы разместили его как комментарий. За исключением log10 (2^64) = 19.2659, поэтому 19 не 20 цифр и log10 (2^128) = 38,5318, поэтому всего 38 цифр. – Clifford
'long double' может или не может обеспечить дополнительную точность над' double' в зависимости от компилятора и в любом случае может не поддерживаться 'fprintf'. В целом 'double' хорош только для 15 десятичных значащих цифр. Но факториалы всегда являются положительными целыми числами, поэтому любой вид плавающей точки является плохим выбором - вы получаете диапазон ценой точности, а для факториала «приближение» редко бывает полезным. – Clifford