这是sqrt函数中的一个错误

Muh*_*mad 3 c++ x86 assembly standard-library x87

我创建了一个应用程序来计算64位范围内的素数,所以当我尝试使用i的sqrt函数计算64位数的平方根时,math.h发现答案是不准确的,例如当输入是~0ull答案应该是~0u但是我得到的是0x100000000哪个不对,所以我决定用汇编x86语言创建我自己的版本,看看这是不是一个bug,这是我的函数:

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]
    }
}
Run Code Online (Sandbox Code Playgroud)

输入是奇数以获得其平方根.当我用相同的输入测试我的功能时,结果是相同的.

我没有得到的是为什么这些函数围绕结果或具体说明为什么sqrt指令结果?

sep*_*p2k 8

sqrt不会舍入任何内容 - 当您将整数转换为double时,您会执行此操作.双精度不能代表64位整数可以不丢失精度的所有数字.具体从2 53开始,有多个整数将表示为相同的double值.

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