3

64ビット範囲の素数を計算するアプリケーションを作成したので、sqrt関数を使用して64ビット数の平方根を計算しようとするとmath.h、たとえば入力が~0ull答えである場合、答えは正確ではないことがわかりまし~0uた。私が得0x100000000たものは正しくないので、これがバグであるかどうかを確認するために、アセンブリx86言語を使用して独自のバージョンを作成することにしました。これが私の関数です。

inline unsigned prime_isqrt(unsigned long long value)
{
    const unsigned one = 1;
    const unsigned two = 2;

    __asm
    {
        test dword ptr [value+4], 0x80000000
        jz ZERO
        mov eax, dword ptr [value]
        mov ecx, dword ptr [value + 4]

        shrd eax, ecx, 1
        shr  ecx, 1
        mov  dword ptr [value],eax 
        mov  dword ptr [value+4],ecx

        fild value
        fimul two
        fiadd one
        jmp REST
ZERO: 
        fild value
REST: 
        fsqrt
        fisttp value
        mov eax, dword ptr [value]
    }
}

入力は、平方根を取得するための奇数です。同じ入力で関数をテストすると、結果は同じでした。

私が得られないのは、なぜそれらの関数が結果を丸めるのか、具体的にはsqrt命令が結果を丸めるのかということです。

4

2 に答える 2

8

sqrt何も丸めません-整数を倍精度に変換するときに行います。double は、64 ビット整数が精度を失うことなくすべての数値を表すことはできません。具体的には 2 53から始まる、同じ double 値として表される複数の整数があります。

したがって、2 53を超える整数を double に変換すると、最下位ビットの一部が失われます。これが、(double)(~0ull)18446744073709551615.0 ではなく、18446744073709552000.0 である理由です (または、より正確に言うと、後者は同じ double 数を表すため、実際には前者と等しくなります) )。

于 2012-05-30T12:16:21.277 に答える
0

呼び出している C++ 関数がよくわかりません。sqrtオーバーロードされた名前です。あなたはおそらく望んでいsqrt(double(~0ull))た。sqrtを取るオーバーロードはありませんunsigned long long

于 2012-05-30T12:12:33.297 に答える