当n的数值超大时如何求 n!

目录

 

n数值较小时求解n!的方法:

n数值较大时(>13)求n!的方法:


n数值较小时求解n!的方法:

C语言描述:

#include <math.h>
#include <stdio.h>
int main()
{
    int n,s,i;
    //printf("请输入一个小于13的正整数");
    //scanf("%d",&n);
    s=1;
    n=10;//n的值是用户传入的值,这里为了方便,就直接赋值为10
    for(i=1;i<=n;i++)
    {
        s=s*n;//累乘    
    }
    printf("%ld\n",s);
}

java语言描述:

package test;

/**
 * Create by ZwZ
 * DateTime:2018/10/8 17:26
 * Description :当n的值很小的时候求n!
 */
public class Test1 {
    public static void main(String[] args) {
        int n = 10;//为了方便没有要求用户输入,而是直接使用的固定值10
        int s = 1;
        //累乘
        for (int i = 1;i <= n;i++){
            s= s * i;
        }
        System.out.println(s);
    }
}

在64位的计算机上,Java语言和C语言中int类型都是占有4个字节。所以不管是使用C语言还是Java语言去解决此问题,当n的值过大时就会导致最终结果的不准确。

于是我们就想出了一个更好的解决此问题的办法。

n数值较大时(>13)求n!的方法:

思想:

利用一维数组去存储相对应的存储阶乘之后的结果的每一位所对应的数值。即a[1]存储结果中所对应的个位,a[2]存储结果中所对应的十位。这样子当数组的容量很大时,就可以存储很大的数。

而此思想的实现,最主要的问题在于如何使用这个一维数组内所存储的数据模拟平时的乘法运算。如下:

 我们如果要使用编程去实现的话,首先应该有一个数组去存储每次乘法运算结束之后所产生的结果,其次还要有一个参数用于控制阶乘运算中乘到几结束,也就是n的值(这个值按道理来讲应该是使用你写的用于计算阶乘的这个程序的用户所传过来的),还要有一个变量专门存储进位的数值。以上就是我们笼统的分析的此次编程所要的变量。

思路:

以下是我们用于存储阶乘结果的数组:

 其中m表示阶乘结果的位数。当n的值确定时,m的值就随之确定。方法如下:

由于s = lg(n!)在编程过程中可以利用数学函数去得到,进而也就得到了m的值。其代码如下:

//得到s的值
for(int i=1;i<=n;i++)
{
    s=s+log10(k);
}
//对s取整,得到m的值
m=(int)s+1;

 当m的值即阶乘结果的位数确定后,接下来就需要编程在数组中进行数学乘法运算的模拟。其中应该有一个变量存储进位,以用来对进位进行控制。还要有n参与进来控制乘法循环的次数,即乘到什么时候结束。还要有一个数组对于阶乘的结果进行存储,而且这个数组还要足够大。

for(k=2;k<=n;k++){
    for(j=1;j<=m;j++){
        t=a[j]*k+g;
        a[j]=t%10;
        g=t/10;    
    }
}

 上边的代码即为阶乘运算处的核心代码。其核心在于:对于每一个<=n的值,都会让此值去与之前的阶乘结果的每一位去相乘,乘完之后,将除法运算的商赋值给用于存储进位的变量g(原因在于:如果一个数/10后得到的商大于1的话,就说明在这一位上已经容不下它了,要进位。而进位g就会在j+1之后的for循环中加到下一位上  )如果有这种进位的情况发生的话,那么在数组的现在这一位上就是留的%10后的值,也就是取余的值。如果进位的情况没有发生,那么循环中的数组的这一位上也是留的%10后的值。

以上代码如果只靠理论上去阐述的话可能会比较难理解。我们下面可以试一下几个例子,看看此双重循环的执行过程:

以上就是对于大整数运算中n!计算的描述。大家如果想要更加深入了解其过程的话,可以多写几步,例如当n=6 , 7时。看此算法的整个计算过程是怎么样的。这样有助于对算法的深入理解。以下是算法实现的全部源码(C语言描述):

#include <math.h>
#include <stdio.h>
int main()
{
   int j,k,m,n,a[100000];
   long g,t;
   double s;
   printf("Please input an integer: ");
   scanf("%d",&n);//输入n的值 
   s=0;
   for (k=2;k<=n;k++)
     s+=log10(k);
   //得到n!的位数 
   m=(int)s+1;
   //将m位之后的所有的位的值清零 
   for (k=1;k<=m;k++)
   {
      a[k]=0; 
   } 
   a[1]=1;//给a[1]赋值 
   g=0;
   //用于阶乘的运算 
   for (k=2;k<=n;k++)
   { 
      for (j=1;j<=m;j++)
      {
         t=a[j]*k+g;
         a[j]=t%10;
         g=t/10;
      }
   } 
  //输出运算结果 
  for (k=m;k>=1;k--)
  { 
    printf("%1d",a[k]);
  }
}

 

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值