优化阶乘算法的探索

优化阶乘算法的探索优化阶乘算法的探索中国地质大学(武汉)  陈海丰 阶乘(factorial)是基斯顿·卡曼(ChristianKramp,1760–1826)于1808年发明的运算符号。阶乘,也是数学里的一种术语,是指从1乘以2乘以3乘以4一直乘到所要求的数。例如所要求的数是4,则阶乘式是1×2×3×4,得到的积是24,24就是4的阶乘。如果所要求的数是n,则阶乘式是1×2×3×……×n,设

大家好,又见面了,我是你们的朋友全栈君。

优化阶乘算法的探索

中国地质大学(武汉)   陈海丰

 

阶乘(factorial)是基斯顿·卡曼(Christian Kramp, 1760 – 1826)于1808年发明的运算符号。阶乘,也是数学里的一种术语,是指从1乘以2乘以3乘以4一直乘到所要求的数。例如所要求的数是4,则阶乘式是1×2×3×4,得到的积是24,24就是4的阶乘。如果所要求的数是n,则阶乘式是1×2×3×……×n,设得到的积是x,x就是n的阶乘。在表示阶乘时,就使用“!”来表示,如n阶乘,就表示为n!。
    根据阶乘的定义,我们不难得到求解阶乘的递推式。

            …………………………………(1)

当n值很小时,在计算机中可以直接用整型数据的运算就可以解决了,可是当n值很大,比如n=10000时计算结果就不能用现有的数据类型来存放了,因为它的位数已远远超过了现有的数据类型(如10000!有35660位)。为了解决所有数据类型都无法存放这样一个庞大的数据,目前大家采用的是将一个大数一位一位的存放到一个字符型数组或整型数组中,然后要运算时对其每一位进行单独运算,这样就解决了庞大数据的存放问题。但具体怎样对两个都比较大的数的作乘法运算呢?这就要利用大整数的高精度运算。如A,B都是位数比较多的大整数,现在要作A*B运算。小学时我们作45*12是先把12中的2与45的个位5相乘,再把2与45的十位4相乘,然后同样再把12中的1与45中的每一位从低到高依次相乘。在这里我们也可以模拟45*12,把A中每一位从低到高与B中的个位相乘,与后再与B中的十位相乘,依次类推,最后把所有的结果对应相加就可以得到所要求的结果了。

具体代码(一):

#include <stdio.h>

#include <string.h>

 

char a[40000], b[10];

int c[40000];

int main()

{    

    int n;

     while(scanf(“%d”, &n) != EOF){

        int la, lb, lc, i, j, k, k1;

        if(n == 0 || n == 1){

              printf(“1/n”);

              continue;

         } //几种特殊情况

        if(n == 2){

              printf(“2/n”);

              continue;

         }

        a[0] = 50;   //初始化使是最先相乘的数从开始

         for(k1 = 3;k1 <= n;k1++){                  

              k = k1;          

              for(j = 0;k;j++){

                   b[j] = k % 10 + 48;

                   k /= 10;

              }          

              la = strlen(a);

              lb = strlen(b);  

              memset(c, 0, sizeof(c));      

              for(i = 0;i < la;i++){

                   for(j = 0;j < lb;j++){          

                       c[i + j] += (a[i] – 48) * (b[j] – 48);

                       //循环相乘,结果存放到另一数组中         

                       c[i + j + 1] += c[i + j] / 10;   //进位         

                       c[i + j] %= 10;

                       lc = i + j + 1;   //当前位     

                   }

              }

              if(c[lc] == 0) lc–;    

              for(i = lc;i >= 0;i–)

                   for(i = lc;i >= 0;i–) a[i] = c[i] + 48;

                   //将结果复制到数组a中,再和b数组相乘

         }

         for(i = lc;i >= 0;i–){   //输出结果时从数组的最后一个开始输出

              printf(“%c”, a[i]);

        }

         printf(“/n”);    

         memset(a, 0, sizeof(a)); //将数组全部初始化

         memset(b, 0, sizeof(b));        

     }

     return 0;

}

上面程序可以计算大数的阶乘,但是效率非常的低,如10000!的阶乘需要2000Ms左右,所以这种算法并不能解决实际问题。考虑到上面的程序是一位一位的把一个大数存放下来,然后相乘时也是一位一位的进行的。然后我想到定义一个整型的数组,每一位不是存放一位而是存放五位,这样相加,相乘的次数就是原来的 ,10000!运算时间是200Ms,是原来的 。

具体代码(二):

 

#include<stdio.h>

 

int main()  

{    

     int n;

     printf(“请输入一个整数N(0~20000):/n”);    

     while(scanf(“%d”, &n) != EOF){      

         int s[16000] = {0}, j, i, k = 0, t = 0, p = 0;

         long sum = 0;        

         s[0] = 1;  

         for(j = 1;j <= n;j++){  

              for(i = 0;i <= t;i++){  

                   sum = s[i] * j + p;  

                   p = 0;  

                   if(sum > 99999){  

                       s[i] = sum % 100000;   //每一位存放位         

                       p = sum / 100000;          

                       if(t == i){

                            t++;

                            s[t] = 0;

                       }  

                   }  

                   else s[i]=sum;  

              }  

         }  

         printf(“%d!=”, n);

         printf(“%d”, s[t]);  

         for(i = t – 1;i >= 0;i–){    

              printf(“%05d”,s[i]);  

         }  

         printf(“/n/n”);

         printf(“请再输入一个整数N(0~20000):/n”);

     }  

     return 0;  

}

 

当然在程序中可以把存放大数的数组定义成长整型(long)则每一个数组元素可以存放更多位,10000!的运行时间可以缩短到50Ms。在实践中算法的可行性是非常重要的,算法要不断的优化才能有机实际作用,所以要学会优化算法,提高自己的编程能力。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cschf/archive/2008/05/28/2491623.aspx

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/164010.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ReadProcessMemory会被检测到吗?_仅完成部分readprocess如何解决

    ReadProcessMemory会被检测到吗?_仅完成部分readprocess如何解决ReadProcessMemory从特定进程的内存里读取数据。被读取的整个位置应该是可读的否则操作会失败。BOOLWINAPIReadProcessMemory(__in  HANDLEhProcess,__in  LPCVOIDlpBaseAddress,__out LPVOIDlpBuffer,__in  SIZE_TnSize

    2022年10月4日
    0
  • date函数

    date函数

    2021年10月31日
    43
  • 有什么办法可以实时监控微信_微信被监控有什么特征

    有什么办法可以实时监控微信_微信被监控有什么特征如何同步员工微信聊天记录,员工微信监控管理?这就教你如何操作!企业员工微信怎么更好管理?如何微信监控聊天记录?工作手机管理系统实现员工企业微信聊天全程记录,敏感行为词全程监控,敏感行为监督,私单,飞

    2022年8月6日
    3
  • IP地址(分类)、子网掩码、网络号、主机号、子网号

    IP地址(分类)、子网掩码、网络号、主机号、子网号IP地址IP地址被用来给Internet上的电脑一个编号。大家日常见到的情况是每台联网的PC上都需要有IP地址,才能正常通信。我们可以把“个人电脑”比作“一台电话”,那么“IP地址”就相当于“电话号码”,而Internet中的路由器,就相当于电信局的“程控式交换机”。IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。例:点分十进IP地址(100.4.5.6),

    2022年6月24日
    18
  • LNK2001:无法解析外部符号_sprintf

    LNK2001:无法解析外部符号_sprintfLNK2001:无法解析外部符号_sprintf与LNK1104:无法打开文件“kernel32.lib”_臻訾胃的博客-CSDN博客从网上下载一个VS的demo,编译之后老是报LNK2001:无法解析外部符号_sprintf的错误,找了好久,发现在项目属性->链接器->输入->附加目录依赖项添加legacy_stdio_definitions.lib即可解决问题。但不知道legacy_stdio_definitions.lib这玩意儿干啥的,有兴趣的自己百度吧..

    2022年6月28日
    52
  • pycharm中mysql连接失败_pycharm连接mysql数据库连接不上[通俗易懂]

    pycharm中mysql连接失败_pycharm连接mysql数据库连接不上[通俗易懂]代码其实很简单,只有一小段,是在pycharm上运行的,所用的python版本为2.7,mysql版本为5.7.21#-*-coding:UTF-8-*-importreimportMySQLdbif__name__==’__main__’:#打开数据库conn=MySQLdb.connect(host=’localhost’,port=3306,user=’root’,pa…

    2025年6月21日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号