博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
高精度阶乘的运算
阅读量:6042 次
发布时间:2019-06-20

本文共 1922 字,大约阅读时间需要 6 分钟。

阶乘:1x2x3x4.....N,仿照2的N次方的手法,只不过这次从前往后计算,得到的数从左往后,依次为个位十位百位...等等。

例如:021,表示120

#include 
using namespace std;#define max 100/*保存结果的数组长度*/int f[max];int main(){ int n=10; /*n表示n!,自由修改*/ f[0] = 1; for(int i = 2;i <= n;i++) { int c = 0;/*进位值*/ for(int j = 0;j < max;j++)/*整个数组乘一遍*/ { int s = f[j] * i + c; f[j] = s % 10; c = s / 10; } } for(int k = max - 1;k >= 0;k--) /*扫描清除右边的0*/ if(f[k]) break; for(i = k;i >= 0;i--) /*从右往左打印结果*/ cout<

这个算法的一个缺点是,每次都要把数组乘一遍,有什么办法能优化它呢?

一、首先对阶乘结果的位数进行优化,采用的思路是:

int f(int n){    double a=0.0;    while(n)    {        a+=log10(n);        n--;    }    return (int)a+1;}

得到位数的好处是,不用事先定义一个大数组,而是需要多少位就分配多大的数组(堆分配),这是解决空间的问题。

接着,再想着时间的问题,假如定义100个元素的数组,每次代码都要从数组的首位一直到末位乘以一个数,假如算到5!=120的时候,数组存储的情况是:
0  2  1  0  0  0  0  0  0....
现在又要这个数组每位再乘以6,则右边是一连串的0,还有必要再依次乘一遍吗?设想了几种可能,均告失败。记录一下错误的尝试:
这种思路是,初始化时先把数组全部置为某个字符,比如'C’,而在循环相乘的判定中,如果没有进位,且下一个数组元素是标志‘C',就停止循环,但是忽略了这个标志’C'也需要参与运算,于是失败!
现在设想,如果把已经得到结果的最末位数做一个监视哨flag,每次循环乘数只要乘到这个监视哨就结束,就可以解决这个问题!如图所示:
flag作为监视哨,必定指向每次运算之后的结果的最末位。假如现在j又要乘以6,从第一位0开始,一直移位到监视哨。即:j<=flag。
第二种情况,假如在监视位出现进位了,依然还要继续乘下去,于是,得到另一个条件:f>0,只要有进位也要继续往下乘。
第三种情况:假如现在结果已经是0  2  7,(720),再乘以7之后,得到:
0  4  0  5,由于flag现在还指向第三位,所以要把位置提到末位,也就是说,每次循环完成之后,还要提升监视哨的位置.
到此,问题算是解决了!
这个模型相当于,如何在数组的循环运算中截断到某个位置!(主要判定监视哨的位置和中止的条件

/*算法改进,效率提升很多!*/#include 
using namespace std;#define max 30000int a[max];int main(){ int n,x; cin>>n; a[0]=1; for(int i=2,flag=0;i<=n;i++)/*监视哨初始指向数组首位*/ { for(int f=0,j=0;j<=flag || f>0;j++)/*j未到监视哨,或者有进位*/ { x=a[j]*i+f; f=x/10;/*进位*/ a[j]=x%10; } while(a[j]==0)/*提升监视哨的位置,j有两种可能的位置*/ j--; flag=j; } while(flag>=0) /*输出结果*/ { cout<

转载于:https://www.cnblogs.com/tinaluo/p/5325140.html

你可能感兴趣的文章
【转载】 [你必须知道的.NET]目录导航
查看>>
数据存储小例
查看>>
Spring Boot 配置优先级顺序
查看>>
C++中构造函数详解
查看>>
电商网站中添加商品到购物车功能模块2017.12.8
查看>>
android 模拟器 hardWare 属性说明
查看>>
六款值得推荐的android(安卓)开源框架简介
查看>>
max_element( )
查看>>
java中的类
查看>>
Java并发_volatile实现可见性但不保证原子性
查看>>
百度地图添加带数字标注
查看>>
【luogu 1908】逆序对
查看>>
pthread_create线程创建的过程剖析(转)
查看>>
android存储访问框架Storage Access Framework
查看>>
Android 键盘模式详解
查看>>
git 重命名
查看>>
Spring Boot注解学习(一)
查看>>
源码解析--android自定义View(一)
查看>>
@RestController和@Controller的区别
查看>>
xcode4.5 如何找到以前的iphone模拟器
查看>>