分享

大数阶乘题解

 印度阿三17 2018-10-27

题目来源:校软件班第二周作业第一题

参考:阶乘,递归函数,C语言常见数据类型范围,算术溢出,高精度算法

 

阶乘:

一个正整数的阶乘(factorial)是所有小于及等于该数的正整数,并且0的阶乘为1。自然数n的阶乘写作n!。1808年,基斯顿·卡曼引进这个表示法。 亦即n!=1×2×3×...×n。阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n。   递归函数: 一个函数可以调用其他函数,而当它调用自己的时候,就称其为递归(注意:递归函数必须要有终止条件)   C语言常见数据类型范围: signed 和 unsigned 分别对应 有符文  和   无符号   字节数:  用sizeof()来求,例如 sizeof(int)==4 位数 即bit数  : 一个字节是8位,所以 sizeof(int)的位数是32位 取值范围:  2进制下的最大取值 转换成的 10进制数       例如:sizeof(int)的位数是32位,二进制下除最高位符号位为0(表示正数),剩下31位取1,相加得 2147483647       注意:剩下31位下标是0-30,最高位是2^30。        算术溢出:算术溢出(arithmetic overflow)是指计算机进行算术运算产生的结果超出机器所能表示的范围。 深入理解:https://www.jianshu.com/p/ffc97c4d2306      https://blog.csdn.net/itworld123/article/details/78914969   高精度算法:计算机对于超大数据的一种模拟加,减,乘,除,乘方阶乘,开方等运算。---重点是模拟!       模拟谁呢?。。当然是模拟人啊,你想想人是怎么计算加减乘除的。 入门详解:https://blog.csdn.net/zsjzliziyang/article/details/82050337?utm_source=blogxgwz0   一种寻常的思路是直接递归:
#include<stdio.h>
int fac(int n){
    if(n<=1) return 1;
    return n*fac(n-1);
}
int main(){
    int n;
    scanf("%d",&n);
    printf("%d",fac(n));
    return 0;
}

但会出现一个问题,在20!的时候,出现了负数?(算术溢出)

事实上,在第13!的时候,int就不够储存了,int的最大值是 2147483647

13!正确的答案是  6 227 020 800

而这段代码的错误答案是:

 

一种简单的解决方式是,是用取值范围比int还大的数据类型来储存

比如:long long ,double,long double  etc....

例如 long long

但是,在21!的时候。。。

 

这算是基本满足了题目的要求吧,但对于进阶的数据范围200<n<1000,还是远远不够,

也许你想到了用其他类型,比如最大的long double,4932位

但是。。mingw使用windows的C运行库,里面的printf不支持long double的输出(你可以在linux环境下试试)

也许你试了试就会发现,看似4932位计算的如此之多,但long double的有效位只有18-19位,所以后面的4000多位,全部是0。

那怎么办呢??

 

用模拟的思想,

我们人是怎么进行加减乘除运算的?。

相信聪明的你已经想到了幼儿园老师交的办法

竖式计算:

指在计算过程中列一道竖式计算,使计算简便。加法计算时相同数位对齐,若和超过10,则向前进1。

减法计算时相同数位对齐,若不够减,则向前一位借1当10。

 

很简单易懂的思想对吧,那怎么实现呢?,如何把每一位数都存起来呢?

当然是用数组啦。。。。

 1 #include<stdio.h>
 2 const int N=10000;// 定义一个不可改变的常数N 
 3 int a[N];
 4 int main(){
 5     int n;
 6     scanf("%d",&n);
 7     int s=0;
 8     a[0]=1;
 9     int ans=0;
10     for(int i=1;i<=n;i  ){
11         int t=0;//进位
12         for(int j=0;j<N;j  ){//模拟计算
13             s=a[j]*i t;//每一位乘以i,再加上t 
14             a[j]=s;//余数 
15             t=s/10;
16         }
17     }
18     int k=N-1;
19     while(a[k]==0) k--;//删除前导0 
20     for(int i=k;i>-1;i--) printf("%d",a[i]);
21     printf("\n\n%d\n",k);//计算位数 
22     return 0;
23 }

 

这是定义了10000位,假如需要计算更大的数,可以改变N的值。

来源:http://www./content-4-71951.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多