大数阶乘的计算是一个有趣的话题,从中学生到大学教授,许多人都投入到这个问题的探索和研究之中,并发表了他们自己的研究成果。如果你用阶乘作关键字在google上搜索,会找到许多此类文章,另外,如果你使用google学术搜索,也能找到一些计算大数阶乘的学术论文。但这些文章和论文的深度有限,并没有给出一个高速的算法和程序。

我和许多对大数阶乘感兴趣的人一样,很早就开始编制大数阶乘的程序。从2000年开始写第一个大数阶乘程序算起,到现在大约己有6-7年的时光,期间我写了多个版本的阶乘计算器,在阶乘计算器的算法探讨和程序的编写和优化上,我花费了很大的时间和精力,品尝了这一过程中的种种甘苦,我曾因一个新算法的实现而带来速度的提升而兴奋,也曾因费了九牛二虎之力但速度反而不及旧的版本而懊恼,也有过因解一个bug而通宵敖夜的情形。我写的大数阶乘的一些代码片段散见于互联网络,而算法和构想则常常萦绕在我的脑海。自以为,我对大数阶乘计算器的算法探索在深度和广度上均居于先进水平。我常常想,应该写一个关于大数阶乘计算的系列文章,一为整理自己的劳动成果,更重要的是可以让同行分享我的知识和经验,也算为IT界做一点儿贡献吧。

 

  我的第一个大数阶乘计算器始于2000年,那年夏天,我买了一台电脑,开始在家专心学习VC,同时写了我的第一个VC程序,一个仿制windows界面的计算器。该计算器的特点是高精度和高速度,它可以将四则运算的结果精确到6万位以内,将三角、对数和指数函数的结果精确到300位以内,也可以计算开方和阶乘等。当时,我碰巧看到一个叫做实用计器的软件。值得称颂的是,该计算器的作者姜边竟是一个高中生,他的这个计算器功能强大,获得了各方很高的评价。该计算的功能之一是可以计算9000以内阶乘的精确值,且速度很快。在佩服之余,也激起我写一个更好更快的程序的决心,经过几次改进,终于使我的计算器在做阶乘的精确计算时 (以9000!为例),可比实用计算器快10倍。而当精确到30多位有效数字时,可比windows自带的计算器快上7500倍。其后的2001年1月,我在csdn上看到一个贴子,题目是“有谁可以用四行代码求出1000000的阶乘”,我回复了这个贴子,给出一个相对简洁的代码,这是我在网上公布的第一个大数阶乘的程序。这一时期,可以看作是我写阶乘计算器的第一个时期。

  我写阶乘计算器的第二个时期始于2003年9月,在那时我写了一组专门计算阶乘的程序,按运行速度来分,分为三个级别的版本,初级版、中级版和高级版。初级版本的算法许多人都能想到,中级版则采用大数乘以大数的硬乘法,高级版本在计算大数乘法时引入分治法。期间在csdn社区发了两个贴子,“擂台赛:计算n!(阶乘)的精确值,速度最快者2000分送上”和“擂台赛:计算n!(阶乘)的精确值,速度最快者2000分送上(续)”。其高级算的版本完成于2003年11月。此后,郭先强于2004年5月10日也发表了系列贴子,“擂台:超大整数高精度快速算法”、“擂台:超大整数高精度快速算法(续)”和“擂台:超大整数高精度快速算法(续2)”, 该贴重点展示了大数阶乘计算器的速度。这个贴子一经发表即引起了热列的讨论,除了我和郭先强先生外,郭雄辉也写了同样功能的程序,那时,大家都在持续改进自己的程序,看谁的程序更快。初期,郭先强的稍稍领先,中途郭子将apfloat的代码应用到阶乘计算器中,使得他的程序胜出,后期(2004年8月后)在我将程序作了进一步的改进后,其速度又稍胜于他们。在这个贴子中,arya提到一个开放源码的程序,它的大数乘法采用FNT+CRT(快速数论变换+中国剩余定理)。郭雄辉率先采用apflot来计算大数阶乘,后来郭先强和我也参于到apfloat的学习和改进过程中。在这点上,郭先强做得非常好,他在apfloat的基础上,成功地优化和改时算法,并应用到大数阶乘计算器上,同时他也将FNT算法应用到他的<超大整数高精度快速算法库>中,并在2004.10.18正式推出V3.0.2.1版。此后,我在2004年9月9日也完成一个采用FNT算法的版本,但却不及郭先强的阶乘计算器快。那时,郭先强的程序是我们所知的运算速度最快的阶乘计算器,其速度超过久负盛名的数学软件Mathematica和Maple,以及通用高精度算法库GMP。

  

  我写阶乘计算器的第三个时间约开始于2006年,在2005年8月收到北大刘楚雄老师的一封e-mail,他提到了他写的一个程序在计算阶乘时比我们的更快。这使我非常吃惊,在询问后得知,其核心部分使用的是ooura写的FFT函数。ooura的FFT代码完全公开,是世界上运行的最快的FFT程序之一,从这点上,再次看到了我们和世界先进水平的差距。佩服之余,我决定深入学习FFT算法,看看能否写出和ooura速度相当或者更快的程序,同时一个更大计划开始形成,即写一组包括更多算法的阶乘计算器,包括使用FFT算法的终极版和使用无穷级数的stirling公式来计算部分精度的极速版,除此之外,我将重写和优化以前的版本,力争使速度更快,代码更优。这一计划的进展并不快,曾一度停止。

  

  目前,csdn上blog数量正在迅速地增加,我也萌生了写blog的计划,借此机会,对大数阶乘之计算作一个整理,用文字和代码详述我的各个版本的算法和实现,同时也可能分析一些我在网上看到的别人写的程序,当然在这一过程中,我会继续编写未完成的版本或改写以前己经实现的版本,争取使我公开的第一份代码都是精品,这一过程可能是漫长的,但是我会尽力做下去。

菜鸟篇

程序1,一个最直接的计算阶乘的程序

#include "stdio.h"
#include "stdlib.h"
int main(int argc, char* argv[])
{long i,n,p;printf("n=?");scanf("%d",&n);p=1;for (i=1;i<=n;i++)p*=i;printf("%d!=%d/n",n,p);return 0;
}

程序2,稍微复杂了一些,使用了递归,一个c++初学者写的程序

#include   <iostream.h>   long   int   fac(int   n);   void   main()   {   int   n;   cout<<"input   a   positive   integer:";   cin>>n;   long   fa=fac(n);   cout<<n<<"!   ="<<fa<<endl;   }   long   int   fac(int   n)   {   long   int   p;   if(n==0)   p=1;   else   p=n*fac(n-1);   return   p;   }   

程序点评,这两个程序在计算12以内的数是正确,但当n>12,程序的计算结果就完全错误了,单从算法上讲,程序并没有错,可是这个程序到底错在什么地方呢?看来程序作者并没有意识到,一个long型整数能够表示的范围是很有限的。当n>=13时,计算结果溢出,在C语言,整数相乘时发生溢出时不会产生任何异常,也不会给出任何警告。既然整数的范围有限,那么能否用范围更大的数据类型来做运算呢?这个主意是不错,那么到底选择那种数据类型呢?有人想到了double类型,将程序1中long型换成double类型,结果如下:

#include "stdio.h"
#include "stdlib.h"int main(int argc, char* argv[])
{double i,n,p;printf("n=?");scanf("%lf",&n);p=1.0;for (i=1;i<=n;i++)p*=i;printf("%lf!=%.16g/n",n,p);return 0;
}

运行这个程序,将运算结果并和windows计算器对比后发现,当于在170以内时,结果在误差范围内是正确。但当N>=171,结果就不能正确显示了。这是为什么呢?和程序1类似,数据发生了溢出,即运算结果超出的数据类型能够表示的范围。看来C语言提供的数据类型不能满足计算大数阶乘的需要,为此只有两个办法。1.找一个能表示和处理大数的运算的类库。2.自己实现大数的存储和运算问题。方法1不在本文的讨论的范围内。本系列的后续文章将围绕方法2来展开。

WV.21-大数阶乘算法1-序相关推荐

  1. WV.27-大数阶乘算法7-入门篇之二

    入门篇之二 在<大数阶乘之计算从入门到精通―入门篇之一>中,我们给出一个计算阶乘的程序,它采用char型数组存贮大数,1个元素表示1位十进制数字,在计算时,一次乘法可计算一位数字和一个整数 ...

  2. WV.30-大数阶乘算法10-用Stirling逼近近似计算阶乘的探讨与应用

    用Stirling逼近近似计算阶乘的探讨与应用 江苏省赣榆高级中学仲晨 myheimu@yahoo.com.cn [关键词]: Stirling逼近,阶乘,极限论,微积分,数学实验,计算机算法 &qu ...

  3. 大数阶乘算法c语言程序,c/c++开发分享C语言计算大数阶乘的方法

    c/c++开发分享 问题描述 输入一个正整数n,输出n!的值. 其中n!=1*2*3*-*n. 算法描述 n!可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法.使用一个数组a来表示一个 ...

  4. c语言求大数阶乘思路,大数阶乘的c语言算法心得

    由于大数阶乘的位数超出了int的表示范围,我们只能用一个数组来放置它,那么首先确定结果数组的大小,这个可以根据阶乘位数的计算公式来计算,这里有个关键点,在定义数组的时候可以先给出一个指针,在原则上指针 ...

  5. c语言大整数阶乘计算器,大数阶乘_yuanmercu_oxxdl_新浪博客

    菜鸟篇 程序1,一个最直接的计算阶乘的程序 #include "stdio.h" #include "stdlib.h" int main(int argc, ...

  6. NYOJ 27 大数阶乘

    大数阶乘 时间限制:3000ms  |  内存限制:65535KB 难度:3 描述 我们都知道如何计算一个数的阶乘,可是,如果这个数很大呢,我们该如何去计算它并输出它? 输入 输入一个整数m(0< ...

  7. 阶乘之和 大数阶乘之和

    情况一:不考虑大数的情况 算法思想:直接上代码,简单易懂. 代码描述: int fac(int n){int p=1, sum=0;for(int i=1; i<=n; i++){p = p*i ...

  8. c语言22阶乘太大,C语言计算大数阶乘的方法

    C语言计算大数阶乘的方法,整数,数组,阶乘,本文,格式 C语言计算大数阶乘的方法 易采站长站,站长之家为您整理了C语言计算大数阶乘的方法的相关内容. 本文实例为大家分享了C语言计算大数阶乘的具体代码, ...

  9. 阶乘计算之大数阶乘与快速取模阶乘计算

    大数阶乘的常规运算 即数学的模拟运算.一位一位的乘,有进位就进位. #include <bits/stdc++.h> #define _xx ios_base::sync_with_std ...

最新文章

  1. 【树莓派】制作树莓派最小镜像:img裁剪瘦身
  2. leetcode 169. Majority Element
  3. idea tomcat乱码_Tomcat新手常见问题
  4. cx oracle 配置,cx_Oracle的配置啊。。终于搞出来了
  5. 在git的Bash下进行复制粘贴
  6. 一阶电路中的时间常数_你知道RC电路和RL电路中时间常数的来源么?
  7. 2017年计算机基础知识答题宝典,最全全国计算机基础知识试题及答案考级宝典(2018)..pdf...
  8. c 运算符重载前置++_C ++运算符重载–综合指南
  9. 网站屏蔽搜索引擎的方法
  10. 高项 案例分析重点知识 风险采购合同
  11. walking机器人仿真教程-激光导航-TEB算法导航
  12. Java工程师进阶,Java全栈知识体系
  13. LSB 算法matlab改进版,将二值图嵌入多张灰度图像中
  14. 几种微弱信号处理电路
  15. MeGui原滤镜使用心得
  16. linux内核vga参数,LINUX grub 修改VGA参数
  17. VBA 对 range() 或 cells() 的内容格式的修改, 如 range.address(0,0) cells().formulaR1C1
  18. python正则表达式介绍
  19. 研究团队开发AI系统,仅通过足迹来识别身份
  20. 队列和堆栈 --- 先进先出和先进后出

热门文章

  1. 我是那个逼走创业合伙人的CEO,我有话说!
  2. 使用VS code 连接远程linux服务器 —— VSCODE clangd插件 |CSDN创作打卡
  3. 列表含有子列表展开成一个列表
  4. 微信WP8 终端SDK新手使用指南
  5. 默认计算机网络密码是多少,睿因路由器默认无线密码是多少?
  6. 【shell命令】拆分、合并、排序、比较文件
  7. android hook 多线程,从零编写Android Hook Framework
  8. 并发-FutureTask
  9. 数说CS|北大信科保研生源大起底
  10. 如何从数据库中筛选出达成指定里程碑节点的项目_房地产企业如何搭建运营管理体系...