C语言中大数的阶乘计算
在我的C代码中,我想计算范围为1到100的数字的阶乘。对于较小的数字,该函数起作用,但对于较大的数字(例如100!),它返回不正确的结果。有没有办法处理C中大数的阶乘 我使用的编译器是gcc v4.3.3。 我的代码如下:C语言中大数的阶乘计算,c,algorithm,C,Algorithm,在我的C代码中,我想计算范围为1到100的数字的阶乘。对于较小的数字,该函数起作用,但对于较大的数字(例如100!),它返回不正确的结果。有没有办法处理C中大数的阶乘 我使用的编译器是gcc v4.3.3。 我的代码如下: #include <stdio.h> #include <math.h> double print_solution(int); int main(void) { int no_of_inputs, n; int c
#include <stdio.h>
#include <math.h>
double print_solution(int);
int main(void)
{
int no_of_inputs, n;
int ctr = 1;
scanf("%d",&no_of_inputs); //Read no of inputs
do
{
scanf("%d",&n); //Read the input
printf("%.0f\n", print_solution(n));
ctr++;
} while(ctr <= no_of_inputs);
return 0;
}
double print_solution(int n)
{
if(n == 0 || n == 1)
return 1;
else
return n*print_solution(n-1);
}
#包括
#包括
双打印解决方案(int);
内部主(空)
{
int无输入,n;
int ctr=1;
scanf(“%d”,&无输入);//读取无输入
做
{
scanf(“%d”,&n);//读取输入
printf(“%.0f\n”,print_溶液(n));
ctr++;
}当(ctr我猜这是因为您溢出了整数范围,该范围高达约20亿。如果使用无符号整数,您最多可以获得40亿,但除此之外,您还必须使用。没有标准的C数据类型能够准确地处理大到100%的数字。您唯一的选择是使用,无论是通过库还是自己完成。>
如果这只是一个爱好项目,我建议你自己尝试一下。这是一种有趣的锻炼。如果这是与工作相关的,使用一个已有的图书馆
您通常会得到的最大C数据类型是64位整数。100!的顺序为10157,这至少需要525位才能准确地存储为整数。100!=933262154439415268169923885626670049071596826643816214685929
6389521759999322991560894146397156518286253697920827223758251185210
916864000000000000000000000000
不能用整型或长型来表示这么大的数字。100阶乘是巨大的,准确地说,它是9332621544394152681699238856266700490715968264381624685923895217
59999322991560894146397615651828625369792082722375825118521091686400
00000000000000
也许你应该使用bignum库,比如。它有很好的文档,相当一致的界面,速度,如果你在Linux上,你的发行版可能有一个包(我想我的默认安装了它)这肯定是由于溢出。你需要一种表示大数字的方法(unsigned long
甚至不能覆盖21!).您可以尝试使用“unsigned long long”类型,但这是内置类型的最大值。
我建议(正如克莱特斯已经提到的)要么使用已知的大数实现,要么自己编写一个。“这是一个很好的练习”x2.如果你不想使用bigint库,那么使用stdlib最好使用long double
和tgamal()
frommath.h
:
long double fact(unsigned n)
{
return tgammal(n + 1);
}
这将使您在x86上获得精度为18位小数的100!
(即80位长双精度
)
确切的实现也没有那么复杂:
#include <math.h>
#include <stdio.h>
#include <string.h>
void multd(char * s, size_t len, unsigned n)
{
unsigned values[len];
memset(values, 0, sizeof(unsigned) * len);
for(size_t i = len; i--; )
{
unsigned x = values[i] + (s[i] - '0') * n;
s[i] = '0' + x % 10;
if(i) values[i - 1] += x / 10;
}
}
void factd(char * s, size_t len, unsigned n)
{
memset(s, '0', len - 1);
s[len - 1] = '1';
for(; n > 1; --n) multd(s, len, n);
}
int main(void)
{
unsigned n = 100;
size_t len = ceill(log10l(tgammal(n + 1)));
char dstr[len + 1];
dstr[len] = 0;
factd(dstr, len, n);
puts(dstr);
}
#包括
#包括
#包括
void multd(字符*s,大小长度,无符号n)
{
无符号值[len];
memset(值,0,sizeof(无符号)*len);
对于(尺寸i=len;i--;)
{
无符号x=值[i]+(s[i]-'0')*n;
s[i]=“0”+x%10;
如果(i)值[i-1]+=x/10;
}
}
无效事实(字符*s,大小长度,无符号n)
{
memset(s,'0',len-1);
s[len-1]=“1”;
对于(;n>1;--n)multd(s,len,n);
}
内部主(空)
{
无符号n=100;
尺寸长度=天花板(log10l(t加仑(n+1));
字符dstr[len+1];
dstr[len]=0;
factd(dstr,len,n);
看跌期权(dstr);
}
每个人都在告诉你正确答案,但还有几点需要进一步说明
您最初使用double获得更大范围的想法不起作用,因为double无法精确存储此数据。它可以进行计算,但需要大量舍入。这就是bigint库存在的原因
我知道这可能是一个来自教程或示例网站的示例,但在某些情况下,执行无限递归会让你感到痛苦。你有一个递归解决方案,本质上是一个迭代过程。当你尝试使用更大的值运行程序时(尝试10000),你会理解为什么这个网站会被命名为它
一种简单的迭代方法如下
int answer, idx;
for (answer = 1, idx = 1; idx <= no_of_inputs; idx++ ) {
answer = answer * idx;
}
printf("Factorial of %3d = %d\n", no_of_inputs, answer);
int-answer,idx;
对于(answer=1,idx=1;idx如果您只想使用标准数据类型,而不需要精确的答案,那么计算n!的对数,而不是n!本身。n!的对数很容易用双精度(除非n很大) 不要使用递归算法,我认为它是超慢的,即使它被缓存,也会很慢。这只是你应该考虑的事情。
这是因为当您调用事实(100)时,实际上并没有运行它100次,而是实际运行该函数5050次。这是不好的,如果缓存它,那么它可能会运行100次,但是,使用if语句运行函数调用然后运行循环的速度仍然较慢
double print_solution(int n)
{
double rval = 1;
unsigned int i;
for( i = 1; i <= n; i++ ) {
rval *= i;
}
return rval;
}
双打印解决方案(int n)
{
双rval=1;
无符号整数i;
对于(i=1;i要近似计算大数的阶乘,可以采用以下方法:
n! = n * (n-1)!
so log(n!) = log(n) + log(n-1!)
n!=n*(n-1)!
所以log(n!)=log(n)+log(n-1!)
现在,您可以使用动态编程来计算log(n!)并计算
n!as(base)^(log value)除了其他人的建议外,我建议您熟悉您实际使用的任何计算机/平台的基本类型(int、long、long等)的存储限制。(“如果有疑问,请打印更多信息!”)
早期的一张海报提到80位精度限制,但这是x86 CPU所特有的
另一个人多次引用ISO C90,尽管C99是最新的标准;即使许多编译器还没有完全实现C99,你可能会发现它们很可能至少支持long-long,这应该对应于>=64位精度。这是我几年前为解决谷歌之谜而做的,它是ses GMP图书馆:
#包括
#包括“gmp.h”
无效事实(mpz_t r,int n){
无符号整数i;
#include <stdio.h>
#include "gmp.h"
void fact(mpz_t r,int n){
unsigned int i;
mpz_t temp;
mpz_init(temp);
mpz_set_ui(r,1);
for(i=1;i<=n;i++){
mpz_set_ui(temp,i);
mpz_mul(r,r,temp);
}
mpz_clear(temp);
}
int main(void) {
mpz_t r;
mpz_init(r);
fact(r,188315);
/* fact(r,100); */
gmp_printf("%Zd\n",r);
mpz_clear(r);
return(0);
}
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static char *strfact_mult(char *s, unsigned x) {
unsigned sum = 0;
size_t len = strlen(s);
size_t i = len;
while (i > 0) {
sum += (s[--i] - '0') * x;
s[i] = sum % 10 + '0';
sum /= 10;
}
while (sum) {
len++;
memmove(&s[1], s, len);
s[i] = sum % 10 + '0';
sum /= 10;
}
return s;
}
char *str_fact(char *dest, unsigned n) {
strcpy(dest, "1");
while (n > 1) {
strfact_mult(dest, n--);
}
return dest;
}
void test_fact(unsigned n) {
char s[1000];
printf("%3u %s\n", n, str_fact(s, n));
}
int main(void) {
test_fact(0);
test_fact(4);
test_fact(54);
test_fact(100);
}
0 1
4 24
54 230843697339241380472092742683027581083278564571807941132288000000000000
100 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
#include <stdio.h>
void factorial(int b){
int temp = 0, r, size = 0, x;
int arr[200] = {0};
int l_b = b-1;
while(b>0){
r = b%10;
arr[size++] = r;
b = b/10;
}
while(l_b >= 2){
int i=0;
while(size>0){
x = arr[i]*l_b+temp ;
arr[i++] = x%10;
temp = x/10;
size--;
}
while(temp>0){
arr[i++] = temp%10;
temp = temp/10;
}
size = i; --l_b;
}
for(int k=size-1;k>=0;k--)
printf("%d",arr[k]);//ok i'm taking space here
printf("\n");
}
int main(void) {
// your code goes here
int fact;
scanf("%d\n",&fact);
factorial(fact);
return 0;
}
#!/usr/bin/bc -l
define f(n) {
auto r, i
r = 1
for (i = 1; i <= n; i++)
{
r *= i;
print "n = ", i, ", log2 = ", l(r)/l(2), ", n! = ", r, "\n"
}
}
f(35)
quit
# Key values
# n = 1, log2 = 0.00000000000000000000, n! = 1
# n = 2, log2 = 1.00000000000000000000, n! = 2
# n = 3, log2 = 2.58496250072115618147, n! = 6
# n = 4, log2 = 4.58496250072115618149, n! = 24
# n = 5, log2 = 6.90689059560851852938, n! = 120
# n = 6, log2 = 9.49185309632967471087, n! = 720
# n = 7, log2 = 12.29920801838727881834, n! = 5040
# n = 8, log2 = 15.29920801838727881836, n! = 40320
# n = 9, log2 = 18.46913301982959118130, n! = 362880
# n = 10, log2 = 21.79106111471695352921, n! = 3628800
# n = 11, log2 = 25.25049273335425078544, n! = 39916800
# n = 12, log2 = 28.83545523407540696694, n! = 479001600
# n = 13, log2 = 32.53589495221649912738, n! = 6227020800
# n = 14, log2 = 36.34324987427410323486, n! = 87178291200
# n = 15, log2 = 40.25014046988262176421, n! = 1307674368000
# n = 16, log2 = 44.25014046988262176426, n! = 20922789888000
# n = 17, log2 = 48.33760331113296117256, n! = 355687428096000
# n = 18, log2 = 52.50752831257527353551, n! = 6402373705728000
# n = 19, log2 = 56.75545582601885902935, n! = 121645100408832000
# n = 20, log2 = 61.07738392090622137726, n! = 2432902008176640000
# n = 21, log2 = 65.46970134368498166621, n! = 51090942171709440000
# ...
# n = 34, log2 = 127.79512061296909618950, n! = 295232799039604140847618609643520000000
# n = 35, log2 = 132.92440362991406264487, n! = 10333147966386144929666651337523200000000
# ...
# n = 57, log2 = 254.48541573017643505939
# n = 58, log2 = 260.34339672530400718017
# ...
# n = 98, log2 = 511.49178048020535201128
# n = 99, log2 = 518.12113710028496163045
# n = 100, log2 = 524.76499329005968632625