x86_64 程序集双重比较有时无法按预期工作

x86_64 Assembly double comparison not working as intended, some of the time

我知道浮点数不准确,但我需要一种解决方法。

所以,我需要做一个图遍历,我通过将所有节点放入堆栈,添加到所有邻居的路由,然后添加到所有非邻居的大路由,最后通过并找到最佳路线。它适用于从邻居创建的路由,但它在创建大量路由时中断。

这是相关的代码部分。

这里指定了大路由

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 asks D for better route, but nothing happens: good.

D asks A, finds one and calculates distance as 3.3+5.4=8.7, it's better and replaces it's current route: good.

D asks B, finds one with a distance of 8.7+0=8.7. For some reason this is regarded as better and it's route is replaced: bad.

那么,为什么 ja 条件返回 8.7 > 8.7,但仅在将距离初始化为较大数字的路线上(我尝试减小数字的大小,但产生了相同的结果)?

谢谢。

四舍五入差异是浮点数学中的一个事实。这是解释 here.

如果你只需要找到任意条最佳路线,那么我看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

你会做:

epsilon = 0.001
if x < y - epsilon then
    return LESS_THAN
elseif x > y + epsilon then
    return GREATER_THAN
else
    return EQUAL

2。使用定点数

这比听起来容易;只需将所有内容乘以某个因子即可消除每个数字的小数部分,并根据整数而不是浮点数执行所有计算。

对于距离NNNN.N(即小数点后不超过一位小数),该系数为10。

所以代替:

routeA = 3.3 + 5.4
routeB = 8.7 + 0.0
if routeA > routeB then ...

你会做:

routeA = 33 + 54
routeB = 87 + 0
if routeA > routeB then ...