我创建了一个应用程序来计算64位范围内的素数,所以当我尝试使用sqrt
中的math.h
函数计算64位数的平方根时,我发现答案不是准确的,例如当输入为~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]
}
}
输入是奇数,以获得其平方根。当我使用相同的输入测试我的函数时,结果是相同的。
我没有得到的是为什么这些函数围绕结果或具体为什么sqrt
指令结果?
答案 0 :(得分:8)
sqrt
不会舍入任何内容 - 当您将整数转换为double时,您会执行此操作。双精度不能代表64位整数可以不丢失精度的所有数字。特别是从2 53 开始,有多个整数将表示为相同的双精度值。
因此,如果将高于2 53 的整数转换为double,则会丢失一些最低有效位,这就是为什么(double)(~0ull)
为18446744073709552000.0,而不是18446744073709551615.0(或更准确)后者实际上与前者相同,因为它们代表相同的双数。)
答案 1 :(得分:0)
你不太清楚你正在调用的C ++函数。 sqrt
是一个重载的名称。你可能想要sqrt(double(~0ull))
。没有sqrt
重载需要unsigned long long
。