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

时间:2016-09-16 12:28:54

标签: assembly floating-point x86-64

在三维空间中写两个点之间的函数计算距离。 gdb会话:

48      mulsd   xmm1, xmm0
(gdb) p/f $xmm0
$5 = {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
$6 = {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
$7 = {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
$8 = {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}

目的地登记册中奇怪的是零。 你有什么建议如何在没有得到零的情况下进行乘法运算?

1 个答案:

答案 0 :(得分:1)

由于下溢,你得零。对于x <1,x ^ 2 更接近为零。平方数字使其远离1。

5.3e-315的幅度小于sqrt(smallest denormal double),因此将其平方后得零。 (注意DBL_MIN是最小的归一化正双,但非正规可以更小。)

使用随机垃圾值测试FP数学不是一个好主意,除非你确定你知道指令的作用是什么&#34;常规&#34;像3.14159这样的值... FP数学已经很难了:

  

[浮点]数学很难。

     

你只是不会相信它是多么巨大,令人难以置信的难度。我的意思是,你可能认为很难计算出来自芝加哥和洛杉矶的火车何时发生碰撞,但这只是花生到浮点数学上。

     

- 布鲁斯道森的出色series of articles on tricky FP math stuff

使用p $xmm0.v2_double仅打印xmm0的双重解释。它在屏幕上的噪音要小得多。

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