C语言计算100的阶乘

学习是一个过程 , 打好坚实的基础往往可以起到事半功倍的效果 , 有时候看似浪费时间的把一道题反复研究 , 最后却能带来意想不到的好的结果 . 万丈高楼得有一个好的地基 , 心急吃不到热豆腐 , 这些写给时常急躁的自己 , 希望自己可以时刻不忘慢工出细活的道理 .
100的阶乘是一个十分庞大的数字 , 已经超过了C语言数据类型所能表示的最大数字 . 因此我们需要另外寻找方法来计算这个庞大的数字 .
显然数组是一个内存连续可以保存许多数字的结构 , 那么我们是否可以把这些数字连在一起从而连接成一个大的数字呢?
我个人认为的函数是一个把规律抽象成为一种映射关系的工具 , 那么显然只要我们能够找到乘法的规律就可以把结果表示出来 . 然后把表示的结果存进数组内,然后把数组输出来 , 那么从形式上看就是我们所求的结果 .
首先我们先积累一个生单词

factorial n. 阶乘

下面来说说乘法的规律 , 我们应该如何存进这个巨大的数字 !
假设我们有一个 int a[64]的数组 . 然后下面开始找规律
100 * 99 = 9900
9900 * 98 = 970200
如果这个数字超过了 10000 , 对它取余试试 , 显然余数是0200 ;再对这个数作除以10000的操作 , 得到结果 97 .
那么我们把 97 存在数组元素a[1]里 , 把 0200存在 a[0]里面会怎样呢 ? 接着往下看 :
0200 * 97 = 19400
这个数字又比10000大了 , 继续取余得到 9400 , 把它存在a[0]里面 , 继续除以10000得到 1 ;
这个 1 显然需要进位对吧 , 我们加到刚刚在 a[1] 里的 97 上 , 得到 98 ,
97 * 97 = 9409
由于刚才进位了一个1 , 所以存入 a[1] 中数字应该是 9409 + 1 = 9410
那么显然根据a[1]里存的是高位数字 , a[0]里存的是低位数字
连接起来得到 94109400
计算器验证一下
100 * 99 * 98 * 97 = 94109400
规律是对的 !
那么为什么呢 ?
从这一步分析 :
970200 * 97 = (970000 + 200) * 97 = 200 * 97 + 970000 * 97
根据乘法分配律 , 我们把 200 * 97 存入了a[0] 里面 , 我们把 97 * 97 存入了a[1] 里 ,但是200 * 97 会超过 10000 , 所以要进位
所以要把 200 * 97 /10000 的结果和 97 * 97 相加 .
不懂的要动手亲自算哦,越来越大但是规律仍然一样,眼过千遍不如手过一遍
这里解释一下为什么要除以以及求余的是 10000 .
由于我们是求100的阶乘 , 所以100以内的两个数作乘积运算自然最大值不超过 10000 , 如果是1000的阶乘那就1000以内的两个数的乘积不会超过1000 * 1000 = 1000000.
说到这里 , 那么对每个 a[i]的工作就是
1 . a[i]的值是否超过 10000 , 超过就进位
2. 加上上一个 a[i] 进位的值
3. 数组下标小的保存低位置的值
还是通过这个例子说明
970200 * 97 = (970000 + 200) * 97 = 200 * 97 + 970000 * 97
观察 200 * 97 + 970000 * 97 , 都乘了97 , 97是什么 ? 是第 n 个要乘的数
200 是a[0]存的数 , 97 是a[1]里存的数
好了 , 我们看看这个核心代码

length = 1 ; //乘积没有大于10000,就只在a[0]里存,只循环一次只改变a[0]的值
jinWei = 0 ; //刚开始没大于10000不需要进位 , 进位的值等于0
for(int i = 0 ; i < length ; i++)
{
temp = a[i] * n + remainder ; // 计算的是a[i]的临时结果 , 这一步加上了上一个元素进位的值 , 解决了问题2
jinWei = temp / 10000 ;  // 判断是否需要进位, 解决了问题1
a[i] = temp % 10000 ; // 留下进位后的余数 , 解决了问题3
}
a[i] = jinWei ; // 结束循环后由于i++ , i的值增加了,其实就是到了数组下一个元素 , 并为下一个新的元素附上了进位的值
if(jinWei > 0 ) // 这个表示如果进位就需要对新的数组元素进行同样的for循环内的步骤,所以要增加length的值
length ++ ;

最后这是整个完整的代码实现:

#include<stdio.h>
void factorial(int n)
{
	int a[64]; // 储存结果的数组 
    int jinWei = 0 ; // 进位之后的余数 
     a[0] = 1 ; // 初始化 a[0] 让其第一次运算结果等于 该数本身 
    int length = 1, temp = 1; //
    int i , j ;
    for(i = n ; i > 1 ; i-- )
	{
		jinWei = 0 ;
		for( j = 0 ; j < length ; j++ )
		{
			temp = a[j] * i + jinWei ;
			a[j] = temp % 10000 ;
			jinWei = temp / 10000 ;
		}
		a[j] = jinWei ;
		if(jinWei > 0)
		{
			length ++ ;
		}
	 } 
	 printf("%d",a[length - 1]);
	 for(i = length - 2 ; i >= 0 ; i--)
	 printf("%04d" , a[i]);
 } 
 int main()
 {
 	int n ;
 	scanf("%d",&n);
 	factorial(n);
 }

解释一下为什么要反序输出:
由于我们把最高位保存在了下标最高的元素里,所以要首先输出最高位的数组元素.
有什么地方逻辑不清晰或者很绕的地方欢迎指出 . 学习是一个犯错改错的过程 .共勉 , 各位优秀的程序员们!

  • 62
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值