Assembly x86_64程序集双重比较有时无法按预期工作
我知道浮点不准确,但我需要一种解决方法 所以,我需要做一个图遍历,我把所有的节点放到堆栈中,给所有的邻居添加路由,然后给所有的非邻居添加一个大路由,最后遍历并找到最好的路由。它适用于从邻居创建的路由,但在使用大量数据创建的路由上会中断 下面是代码的相关部分 此处指定了大路线Assembly x86_64程序集双重比较有时无法按预期工作,assembly,floating-point,double,x86-64,Assembly,Floating Point,Double,X86 64,我知道浮点不准确,但我需要一种解决方法 所以,我需要做一个图遍历,我把所有的节点放到堆栈中,给所有的邻居添加路由,然后给所有的非邻居添加一个大路由,最后遍历并找到最好的路由。它适用于从邻居创建的路由,但在使用大量数据创建的路由上会中断 下面是代码的相关部分 此处指定了大路线 movsd xmm0, [big] mov [r11+rax+TAR], r9 movsd [r11+rax+DIS], xmm0 mov [r11+rax+HOP], r9 这里进行了比较,以查看是否找到了更好的路线 u
movsd xmm0, [big]
mov [r11+rax+TAR], r9
movsd [r11+rax+DIS], xmm0
mov [r11+rax+HOP], r9
这里进行了比较,以查看是否找到了更好的路线
ucomisd xmm0, xmm2
ja bMBD
jmp eMBD
bMBD:
mov rax, [r8+ROT]
mov [rax+r13+HOP], r11
movsd [rax+r13+DIS], xmm2
eMBD:
上面的代码块就是问题所在,下面是我相信代码正在做的工作的分解
D要求D提供更好的路线,但什么也没发生:好
D问A,找到一个,计算距离为3.3+5.4=8.7,它更好,并替换它的当前路线:好
D问B,找到一个距离为8.7+0=8.7的。出于某种原因,这被认为是更好的,它的路线被取代:坏
那么,为什么ja
条件返回8.7>8.7,但仅在距离初始化为较大数值的路线上返回(我已尝试减小数值大小,但结果相同)
谢谢。在浮点数学中,舍入差异是一个事实。这是可以解释的 如果您只需要找到任何一条最佳路线,那么我认为
3.3+5.4>8.7+0.0
中没有问题;任何一条路线都可以
如果您需要检索共享相同最佳距离的所有路线,那么我同意您确实需要3.3+5.4
等于8.7+0.0
。
有几种方法可以做到这一点;见下文。对于示例代码,我将使用伪代码而不是汇编代码,因为这个问题并不特定于任何语言
1.忽略细微差别
如果差值的绝对值小于某个小数值(如0.001),则认为数值相等。
这意味着比较逻辑变得稍微复杂一些。
而不是:
if x < y then
return LESS_THAN
elseif x > y then
return GREATER_THAN
else
return EQUAL
routeA = 3.3 + 5.4
routeB = 8.7 + 0.0
if routeA > routeB then ...
你会做:
epsilon = 0.001
if x < y - epsilon then
return LESS_THAN
elseif x > y + epsilon then
return GREATER_THAN
else
return EQUAL
routeA = 33 + 54
routeB = 87 + 0
if routeA > routeB then ...
舍入差异是浮点数学中的一个事实。这是可以解释的 如果您只需要找到任何一条最佳路线,那么我认为
3.3+5.4>8.7+0.0
中没有问题;任何一条路线都可以
如果您需要检索共享相同最佳距离的所有路线,那么我同意您确实需要3.3+5.4
等于8.7+0.0
。
有几种方法可以做到这一点;见下文。对于示例代码,我将使用伪代码而不是汇编代码,因为这个问题并不特定于任何语言
1.忽略细微差别
如果差值的绝对值小于某个小数值(如0.001),则认为数值相等。
这意味着比较逻辑变得稍微复杂一些。
而不是:
if x < y then
return LESS_THAN
elseif x > y then
return GREATER_THAN
else
return EQUAL
routeA = 3.3 + 5.4
routeB = 8.7 + 0.0
if routeA > routeB then ...
你会做:
epsilon = 0.001
if x < y - epsilon then
return LESS_THAN
elseif x > y + epsilon then
return GREATER_THAN
else
return EQUAL
routeA = 33 + 54
routeB = 87 + 0
if routeA > routeB then ...
在
ucomisd
指令后的调试器输出,显示xmm0
、xmm2
和eflags
。如果这是手动调整的asm,请注意索引寻址模式,如[r11+rax+TAR]
。因此,您实际上可以通过使用ALU指令计算寄存器中的地址来保存一个融合域uop,这样所有三个存储都可以微融合。如果您没有备用寄存器,或者ALU UOP是一个瓶颈,但前端(总融合域UOP)没有,那么您不应该更改任何内容。在ucomisd
指令后的调试器输出,显示xmm0
、xmm2
和eflags
。如果是手动调整的asm,注意索引寻址模式,如[r11+rax+TAR]
。因此,您实际上可以通过使用ALU指令计算寄存器中的地址来保存一个融合域uop,这样所有三个存储都可以微融合。如果您没有备用寄存器,或者ALU UOP是一个瓶颈,但前端(总融合域UOP)没有,那么您不应该更改任何内容。