1

我想使用 Cpp 在阶乘中找到零的数量。问题是当我使用非常大的数字时。

#include <stdio.h>
#include <math.h>

long zeroesInFact(long n)
{
long double fact=1;
long double denominator=10.00;
long double zero=0.0000;
long z=0;
printf("Strating loop with n %ld\n",n);
for(int i=2;i<=n;i++)
{
    fact=fact*i;
    printf("Looping with fact %LF\n",fact);
}
printf("Fmod %lf %d\n",fmod(fact,denominator),(fmod(fact,denominator)==zero));
while(fmod(fact,denominator)==zero)
{
    fact=fact/10;
    z++;
}
printf("Number of zeroes is %ld\n",z);
return z;
}

int main()
{
long n;
long x;
scanf("%ld",&n);
for(int i=0;i<n;i++)
{
    scanf("%ld",&x);
    printf("Calling func\n");
    zeroesInFact(x);
}
return 0;
}

我认为这里的问题是

fmod(fact,denominator) 为我提供了 22 阶乘和分母为 10.00(即 0.000)的正确答案。但它给了我 23 阶乘和分母 10.00 的错误答案

4

1 回答 1

3

考虑这是您在数值精度方面的第一课。类型floatdoublelong double存储近似值,而不是精确值,这意味着它们通常不适合这种计算。即使它们对正确答案有足够的精度,通常最好还是使用整数类型来代替,比如int64_tand uint64_t。有时您甚至可以使用 128 位整数类型。(例如__int128,Microsoft Visual Studio 可能提供)

老实说,我认为你很幸运能得到18!through的正确答案22!

如果你的平台上真的是四倍精度,我认为long double你应该能够计算到。30!你在使用时犯了一个错误fmod——你打算使用fmodl.


您在精确度方面的第二个教训是,当您需要大量精确数据时,您的基本数据类型根本不够好。虽然您可以编写自己的数据类型,但最好使用预先存在的解决方案。Gnu Multiple Precision Arithmetic Library (GMP) 是一个很好且快速的库,您可以在 C/C++ 中使用。

或者,您可以切换语言——例如python,整数数据类型是任意精度的(但不如 GMP 快),因此您甚至不必做任何特别的事情。Java 具有BigInteger进行此类计算的类。


你的第三个教训是精确是找到不做的方法。您实际上不需要完全计算23!以找到尾随零的数量。小心地,您可以组织计算以丢弃不需要的额外精度。或者,您可以切换到获取此数字的完全不同的方法,例如 Rob 在他的评论中暗示的方法。

于 2012-05-04T15:05:01.037 回答