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

来源:互联网 发布:赫连勃勃大王知乎 编辑:程序博客网 时间:2024/06/07 22:43

入门篇之二

在《大数阶乘之计算从入门到精通―入门篇之一》中,我们给出一个计算阶乘的程序,它采用char型数组存贮大数,1个元素表示1位十进制数字,在计算时,一次乘法可计算一位数字和一个整数的乘积。该算法具有简单直观的优点,但缺点也是明显的,速度不快,占用内存空间也较多,本文将给出一个改后的程序,有效的克服了这些缺点。

学过80x86汇编的人都知道,8086/8088的CPU可对两个16比特的数相乘,其结果为32比特,80386及其后的32位CPU可对两个32比特的数相乘,结果为64比特(以下写作bit)。8086 CPU等16位CPU已完全淘汰,这是不去讨论它。在32位c语言编译器中,unsigned long(DWORD)型变量可以表示一个32bit的整数,unsigned short(WORD)型变量可表示一个16bit的整数。两个65535以内的数相乘,其结果完全可以存贮在一个unsigned long变量中。另外,在好多32位编译器中,也提供了64bit的整数类型(如在VC中,unsigned __int64可表示一个64bit的整数,在GCC中,long long可表示一个64位的整数)。同理两个40亿以内的数相乘,其结果可以用一个unsigned __int64 型的变量来存储。让一个具有一次可计算两个32bit数乘法能力的CPU一次只计算1个1位10进制数和一个整数的乘法,实在是一种浪费。下面我们提出两种大数的表示法和运算方法。

第一种方法:用WORD型数组表示大数,用DWORD型变量表示两个WORD型变量的乘积。数组的每个元素表示4位十进制数。在运算时,从这个数的最后一个元素开始,依次乘以当前乘数并加上上次的进位,其和的低4位数依然存在原位置,高几位向前进位。当乘数i小于42万时,其乘积加上进位可以用一个DWORD型变量表示,故这个程序可以计算上到42万的阶乘,当计算42万的阶乘时,占用内存空间小于1.1兆字节。至于速度,在计算1000/10000的阶乘时,在迅驰1.7G电脑约需0.015/0.86秒。

 

#include "stdlib.h"#include "stdio.h"#include "math.h" #define PI 3.1415926535897932384626433832795#define RAD 10000typedef unsigned long DWORD;typedef unsigned short WORD;//用stirling公式估算结果长度,稍微算得大一点DWORD calcResultLen(DWORD n,DWORD rad){    double r=0.5*log(2*PI) + (n+0.5)*log(n)-n;    return (DWORD)(r/log(rad)+2);} void calcFac1(DWORD n){    DWORD i,carry,prod,len;    WORD *buff,*pHead,*pTail,*p;if (n==0)              { printf("%d!=1",n); return; } //---计算并分配所需的存储空间 len=calcResultLen(n,RAD);       buff=(WORD*)malloc( sizeof(WORD)*len);      if (buff==NULL)             return ; //以下代码计算n!    pHead=pTail=buff+len-1;    for (*pTail=1,i=2;i<=n;i++)    {for (carry=0,p=pTail;p>=pHead;p--)                  {                     prod=(DWORD)(*p) * i +carry;                     *p=(WORD)(prod % RAD);                      carry=prod / RAD;                  }      while (carry>0)                 {                          pHead--;                          *pHead=(WORD)(carry % RAD);                          carry /= RAD;                  }    }  //显示计算结果  printf("%d!=%d",n,*pHead);    for (p=pHead+1;p<=pTail;p++)printf("%04d",*p);     printf("/n");   free(buff);//释放分配的内存}int main(int argc, char* argv[]){DWORD n;printf("please input n:");scanf("%d",&n);calcFac1(n);return 0;}


 

第二种方法:用DWORD型数组表示大数,用unsigned __int64 表示两个DWORD型变量的乘积。数组的每个元素表示9位十进制数。在运算时,从这个数的最后一个元素开始,依次乘以当前乘数i(i=1..n)并加上上次的进位,其和的低9位数依然存在原位置,高几位向前进位。从算法上讲,这个程序能够计算到40亿的阶乘,在实际计算过程中,仅受限于内存的大小。至于速度,比前一个程序要慢一些,原因在于unsigned __int64的除法较慢。我们将在下一篇文章给出解决方法,下面是采用该方法计算阶乘的代码。

#define TEN9 1000000000void calcFac2(DWORD n){     DWORD *buff,*pHead,*pTail,*p;     DWORD t,i,len;     UINT64 carry,prod;        if (n==0)     { printf("%d!=1",n); return; } //---计算并分配所需的存储空间     t=GetTickCount();     len=calcResultLen(n,TEN9);     buff=(DWORD*)malloc( sizeof(DWORD)*len);     if (buff==NULL)             return ; //以下代码计算n!     pHead=pTail=buff+len-1;     for (*pTail=1,i=2;i<=n;i++)     {                  for (carry=0,p=pTail;p>=pHead;p--)                  {                        prod=(UINT64)(*p) * (UINT64)i +carry;                        *p=(DWORD)(prod % TEN9);                        carry=prod / TEN9;                  }                  while (carry>0)                  {                          pHead--;                          *pHead=(DWORD)(carry % TEN9);                          carry /= TEN9;                  }     }     t=GetTickCount()-t;//显示计算结果      printf("It take %d ms/n",t);     printf("%d!=%d",n,*pHead);     for (p=pHead+1;p<=pTail;p++)       printf("%09d",*p);     printf("/n");    free(buff);//释放分配的内存}


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 华为p7一l09卡顿怎么办 华为p7打不开机怎么办 华为8主板坏了怎么办 华为手机主板坏了怎么办 华为p9文字变英文了怎么办 华为p9plus电池不耐用怎么办 华为mate8手机音量小怎么办 同花顺自选股更新不显示怎么办 华为麦芒定频了怎么办 用线刷宝刷机失败开不了机怎么办 红米手机拨号后黑屏怎么办 sim卡丢了激活码怎么办 电信sim卡未激活怎么办 小米5c老是黑屏怎么办 小米4x黑屏了怎么办 金立s10经常卡屏怎么办 x9来电屏幕不亮怎么办 小米手机拔号黑屏怎么办 小米手机进水黑屏了怎么办 小米6手机黑屏打不开怎么办 小米手机王者荣耀黑屏怎么办 小米5c手机黑屏怎么办 小米2s开机闪退怎么办 小米手机打不开机怎么办 苹果手机打电话闪退怎么办 红米手机通话时黑屏怎么办 小米手机通话时是黑屏怎么办? 华为手机通话时出现黑屏怎么办 微信屏幕变黑了怎么办 乐视手机打不开机怎么办 金立手机屏幕不亮怎么办 笔记本开不了机怎么办屏幕黑屏 红米4刷机失败怎么办 红米手机开不了机怎么办 红米not开不了机怎么办 红米2开不起机怎么办 小米手机免提声音小怎么办 红米手机1s黑屏怎么办 红米2完全黑屏怎么办 红米note3接电话黑屏怎么办 红米note3死机黑屏怎么办