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

これを数値精度の最初のレッスンと考えてください。タイプfloatdouble、およびlong doubleストアの近似値であり、正確な値ではありません。つまり、これらは通常、この種の計算には適していません。正解に十分な精度がある場合でも、通常は代わりに や などの整数数値型を使用する方が適切int64_tですuint64_t。場合によっては、128 ビットの整数型を使用できることさえあります。(たとえば__int128、Microsoft Visual Studio で利用できる可能性があります)

18!正直なところ、 throughの正しい答えを得ることができて幸運だったと思います22!

あなたlong doubleのプラットフォームで真に 4 倍の精度があれば、最大 まで計算できるはずです30!。を使用するときに間違いを犯しました。使用fmodするつもりfmodlでした。


精度に関する 2 番目の教訓は、多くの精度が必要な場合、基本的なデータ型では不十分だということです。独自のデータ型を作成することもできますが、既存のソリューションを使用する方がよいでしょう。Gnu Multiple Precision Arithmetic Library (GMP) は、C/C++ で使用できる優れた高速ライブラリです。

または、言語を切り替えることもできます。たとえば、python整数データ型は任意の精度 (ただし GMP ほど高速ではない) であるため、特別なことを行う必要さえありません。Java には、BigIntegerこのような計算を行うためのクラスがあります。


3 番目の教訓は、精度です。それを使わない方法を見つけることです。23!実際には、末尾のゼロの数を見つけるために完全に計算する必要はありません。注意して、必要のない余分な精度を破棄するように計算を整理できます。または、この番号を取得するまったく別の方法に切り替えることもできます。たとえば、Rob がコメントでほのめかしていた方法などです。

于 2012-05-04T15:05:01.037 に答える