2

このコンパイラでこのコードをコンパイルします。番号については、18446744073709551615 (2^64-1) と書きます。Pelles の実行可能ファイルは「18446744073709551615 は素数です」と言っていますが、GCC の実行可能ファイルは「18446744073709551615 は素数ではありません」と言っています。なぜ結果が異なるのですか?

#include <stdio.h>
#include <math.h>
int main(void)
{
    unsigned long long number;
    printf("number: ");
    scanf("%llu",&number);
    unsigned long trsq=truncl(sqrtl(number));
    char s=1;
    for(unsigned long i=2;i<=trsq;i++) {
        if (number%i==0) {
            s=0;
            break;
        }
    }
    if (s==1) {
        printf("%llu is prime\n",number);
    } else {
        printf("%llu isn't prime\n",number);
    }
    return 0;
}

編集:

私がテストしたところ、gcc は 12 を返し、pelles c は sizeof(long double) に対して 8 を返しました。

4

1 に答える 1

2

C 言語の定義では、数値型のサイズや、オーバーフローや精度の損失が発生した場合に何が起こるかなど、多くのことが指定されていません。そのため、数値型の範囲をチェックしない場合、または浮動小数点を使用する場合、異なる実装 (異なるコンパイラ、異なるハードウェア、異なるオペレーティング システム) で異なる結果が得られるのは一般的です。

本人からの情報提供によるものです。2 つの コメントで、何が起こっているのかについてのもっともらしい説明を以下に示します。確認するペレス C がありません。

ペレスは次のように警告しています。

警告 #2215: 'unsigned long long int' から 'long double' への変換。データが失われる可能性があります。警告 #2215: 'long double' から 'unsigned long int' への変換。データ損失の可能性

推測 #1: 数学的な値 2^64-1 は a で正確に表すことはできませんlong double(2^64-1 には 64 ビットの仮数部が必要であり、多くの実装ではそれほど多くないため、これは可能性が高いです)。正確に表現できる 2^64 に丸められます。

の値numberは 2^64-1 で、unsigned long long. 関数は引数をsqrtl想定してlong doubleいるため、値はその型に変換されます。推測 #1 を考えるとsqrtl、2^64 の値を受け取ります。したがって、結果は 2^32 です。これは整数なのでtruncl、同じ値を返します。

推測 #2: unsigned long32 ビット型です (これは 32 ビット マシンではほぼ標準であり、少なくとも Microsoft コンパイラでは 64 ビット バージョンの Windows でも当てはまります)。

unsigned longが 32 ビット型の場合、値 2^32 でオーバーフローします。浮動小数点値から整数値への変換でオーバーフローが発生した場合に何が起こるかは、C 標準では定義されていません。コンパイラは、必要なことを選択できます。

推測 #3: Pelles C では、浮動小数点値が整数型に変換されると、より小さな整数型に変換する場合と同様に、型のサイズを法としてラップされます。

推測 #3 の下で、値 2^32 を に代入しようとするtrsqと、型unsigned longと幅が 32 ビットであり、0 に設定されます。したがってtrsq、値は 0 になり、forループは 0 回実行され、プログラムはその数値を誤って報告します。プライムです。

簡単な修正は、 に変更trsqすることunsigned long longです。

最大の素因数が平方根に非常に近い場合 (たとえば、数値が素数の 2 乗である場合)、プログラムがいくつかの数値を素数として報告する可能性があることに注意してくださいnumber。そのためtrsq、平方根よりも小さくなり、平方根より小さい最大の整数よりも小さくなることさえあります。

整数の平方根の計算を実行することで、この問題をすべて回避できます。

于 2014-01-31T02:23:06.993 に答える