3

sqrt我创建了一个应用程序来计算 64 位范围内的素数,所以当我尝试使用来自的函数计算 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不四舍五入 - 当您将整数转换为双精度时您会这样做。双精度不能代表 64 位整数可以不损失精度的所有数字。特别是从 2 53开始,有多个整数将表示为相同的双精度值。

因此,如果将大于 2 53的整数转换为双精度数,则会丢失一些最低有效位,这就是为什么(double)(~0ull)是 18446744073709552000.0,而不是 18446744073709551615.0(或者更准确地说,后者实际上等于前者,因为它们代表相同的双精度数)。

于 2012-05-30T12:16:21.277 回答
0

您对正在调用的 C++ 函数不是很清楚。sqrt是一个重载的名字。你可能想要sqrt(double(~0ull)). 没有sqrt需要unsigned long long.

于 2012-05-30T12:12:33.297 回答