【发布时间】:2018-05-20 20:30:54
【问题描述】:
我注意到计算uint64_t 平方根的整数部分比int64_t 复杂得多。请问,有人对此有解释吗?为什么处理一个额外的位似乎要困难得多?
以下内容:
int64_t sqrt_int(int64_t a) {
return sqrt(a);
}
使用 clang 5.0 和 -mfpmath=sse -msse3 -Wall -O3 编译到
sqrt_int(long): # @sqrt_int(long)
cvtsi2sd xmm0, rdi
sqrtsd xmm0, xmm0
cvttsd2si rax, xmm0
ret
但是如下:
uint64_t sqrt_int(uint64_t a) {
return sqrt(a);
}
编译为:
.LCPI0_0:
.long 1127219200 # 0x43300000
.long 1160773632 # 0x45300000
.long 0 # 0x0
.long 0 # 0x0
.LCPI0_1:
.quad 4841369599423283200 # double 4503599627370496
.quad 4985484787499139072 # double 1.9342813113834067E+25
.LCPI0_2:
.quad 4890909195324358656 # double 9.2233720368547758E+18
sqrt_int(unsigned long): # @sqrt_int(unsigned long)
movq xmm0, rdi
punpckldq xmm0, xmmword ptr [rip + .LCPI0_0] # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd xmm0, xmmword ptr [rip + .LCPI0_1]
haddpd xmm0, xmm0
sqrtsd xmm0, xmm0
movsd xmm1, qword ptr [rip + .LCPI0_2] # xmm1 = mem[0],zero
movapd xmm2, xmm0
subsd xmm2, xmm1
cvttsd2si rax, xmm2
movabs rcx, -9223372036854775808
xor rcx, rax
cvttsd2si rax, xmm0
ucomisd xmm0, xmm1
cmovae rax, rcx
ret
【问题讨论】:
-
正如 Zalman 指出的那样,它将 arg 转换为
double(因为这就是您的 C 源代码所做的),因此严格来说它不是 sqrt 的整数部分。并非所有大于 2^53 的整数都可以精确表示为double,因此这可能涉及舍入。 en.wikipedia.org/wiki/Double-precision_floating-point_format
标签: assembly compilation x86 sse square-root