为什么 mulsd 不乘以 xmm* 寄存器

why mulsd does not multiply xmm* registers

正在编写计算三维空间两点间距离的函数space。 gdb 会话:

48      mulsd   xmm1, xmm0
(gdb) p/f $xmm0
 = {v4_float = {5.08412027, 0, 0, 0}, v2_double = {5.3576676113063418e-315, 0}, v16_int8 = {29, -79, -94, 64, 0 <repeats 12 times>}, v8_int16 = {-20195, 16546, 0, 0, 0, 
    0, 0, 0}, v4_int32 = {5.08412027, 0, 0, 0}, v2_int64 = {5.3576676113063418e-315, 0}, uint128 = 3.9528689422358843932327897004554155e-4942}
(gdb) p/f $xmm1
 = {v4_float = {5.08412027, 0, 0, 0}, v2_double = {5.3576676113063418e-315, 0}, v16_int8 = {29, -79, -94, 64, 0 <repeats 12 times>}, v8_int16 = {-20195, 16546, 0, 0, 0, 
    0, 0, 0}, v4_int32 = {5.08412027, 0, 0, 0}, v2_int64 = {5.3576676113063418e-315, 0}, uint128 = 3.9528689422358843932327897004554155e-4942}
(gdb) n
49      movsd   xmm0, xmm2
(gdb) p/f $xmm1
 = {v4_float = {0, 0, 0, 0}, v2_double = {0, 0}, v16_int8 = {0 <repeats 16 times>}, v8_int16 = {0, 0, 0, 0, 0, 0, 0, 0}, v4_int32 = {0, 0, 0, 0}, v2_int64 = {0, 0}, 
  uint128 = 0}
(gdb) p/f $xmm0
 = {v4_float = {5.08412027, 0, 0, 0}, v2_double = {5.3576676113063418e-315, 0}, v16_int8 = {29, -79, -94, 64, 0 <repeats 12 times>}, v8_int16 = {-20195, 16546, 0, 0, 0, 
    0, 0, 0}, v4_int32 = {5.08412027, 0, 0, 0}, v2_int64 = {5.3576676113063418e-315, 0}, uint128 = 3.9528689422358843932327897004554155e-4942}

奇怪的是,目标寄存器中的值为零。 您对如何执行不为零的乘法有什么建议吗?

由于下溢,你得到零。对于 x<1,x^2 更接近 零。对一个数求平方会使它离 1 更远。

5.3e-315 的震级小于 sqrt(smallest denormal double),因此对其求平方结果为零。 (请注意,DBL_MIN 是最小的标准化正双精度数,但非正规化可以更小。)

使用随机垃圾值测试 FP 数学不是一个好主意,除非您确定您知道指令对“常规”值(如 3.14159)的作用...FP 数学已经够难了:

[Floating-point] math is hard.

You just won’t believe how vastly, hugely, mind-bogglingly hard it is. I mean, you may think it’s difficult to calculate when trains from Chicago and Los Angeles will collide, but that’s just peanuts to floating-point math.

-- Bruce Dawson's excellent series of articles on tricky FP math stuff.


使用p $xmm0.v2_double 仅打印xmm0 的双重解释。屏幕上的噪音少了很多。


此外,您应该使用 MOVAPD(或 MOVAPS)在寄存器之间进行复制。如果要与目标寄存器的上部元素合并,请仅使用 MOVSD。