Design: 记录为什么 NaN 位不是完全确定的

创建于 2016-03-22  ·  15评论  ·  资料来源: WebAssembly/design

(我目前不提倡;这样我们才能做出明智的决定并收集材料以作为理由。)

看看Nondeterminism.md , NaN 位部分很突出。 当然线程可以竞争,资源可以耗尽,特性可以添加; 这些都是整体设计的结果。 但是 NaN 位呢? 虚拟机可以更聪明一点并处理这个问题吗? 有两个问题:

当一个操作得到多个 NaN 操作数时,它会传播哪个?

IEEE 754 未指定这一点,但至少 x86、ARM 和 Power 都选择“第一个”操作数,这是一个合理的选择。

然而,在 wasm 级别修复选择将意味着 wasm 实现不能交换浮点加法和乘法,这有时是对 pre-VEX x86 的有用优化,其中指令破坏了它们的一个输入。 此外,它需要任何使用基于 LLVM 的 VM 来教它加法和乘法在 wasm 上不是可交换的。

人们可以合理地争辩说这些不是阻碍,所以如果有强烈的愿望,这个问题理论上是可以解决的。

当一个操作产生一个 NaN 并且没有 NaN 操作数时,符号位是什么?

x86 使用 1,ARM 使用 0。

解决此问题的最简单方法是在每次浮点运算后进行规范化。 这是可行的,尽管一个棘手的问题是当有 NaN 操作数要传播时,0 和 1 都是可能的有效值,因此仅检查 NaN 结果并规范化是不够的; 必须检查 NaN 结果和缺少 NaN 操作数,然后才进行规范化。

在 _every_ 操作之后进行规范化将非常昂贵; 另一种选择是仅在计算的“转义”点进行规范化(然后规范化路径必须基本上重放整个计算流以确定正确的 NaN 输出)。 这是一种改进,但可能仍会增加大量开销。

另一种可能的实现是取消屏蔽无效异常,在生成 NaN 时捕获陷阱,然后执行规范化并返回。 缺点包括使用非默认 CPU 模式,如果生成大量无效值,速度会非常慢。

不幸的是,这些方法有很大的缺点。 除非其他想法浮出水面,或者有非常强烈的愿望,否则这似乎很难解决。


需要注意的另一件事是 NaN 位很难被意外观察到,因此这通常不是主要的可移植性问题。

有没有其他人有任何想法要补充?

clarification floating point

最有用的评论

我想在做出决定之前量化这对性能的影响。 我认为我们的工具链目前还太不成熟,无法进行良好的性能测量(在这个过程中有更长的极点)。 换句话说:我想避免“千刀万剐”。

所有15条评论

需要注意的另一件事是 NaN 位很难被意外观察到

有什么方法可以使它们无法观察或至少是符号位?

鉴于软件很少关心 NaN 非确定性,IMO 应该将其置之不理。 牺牲性能来使它们具有确定性的情况是什么?

以下是观察 NaN 位的方法列表:

  • reinterpret转换
  • store到线性内存并加载具有不同解释的位(或让位在外部观察)
  • 将参数传递给导入函数的call ,或从导出函数返回值
  • copysign符号位到非 NaN

虚拟机可以在每一个之前插入规范化代码; 这就是上面讨论的“在逃逸点规范化”的想法。 store在热路径上很常见,所以这可能仍然相当昂贵。

@qwertie我非常关心它们,我有一个用例依赖于它们的确定性。 但是正如这里讨论的那样,即使没有在规范中,也有办法使其完全确定。

@qwertie 的好处可能包括稍大的可移植性(例如,世界上确实存在不明智地使用 IEEE 754 totalOrder 函数的代码)、稍高的可重复性以及在跨多个节点进行对称计算时更强的不变量。

store在热路径上很常见,所以这可能仍然相当昂贵。

对于这种情况,我们可以总是指定符号值吗? 所以就像如果它被放置在内存中就让它成为1?

@wanderer这本质上是规范化所需要的:检查值是否为 NaN,如果是,则应用一些更正。 它通常是热路径上的额外比较和分支。

我还应该补充一点,我没有对本期提到的任何选项进行基准测试; 欢迎任何人在这里添加任何基准测试。

我强烈倾向于当前的非确定性水平,这有利于性能。
我实际上有点惊讶 wasm 严格定义了 NaN 的尾数位。
虽然这对于今天的处理器来说可能已经足够了,但谁知道未来的处理器可能会出现什么。

如果 wasm 是从高级语言生成的,则该翻译器可以提供一个选项来控制 FP 语义的级别,例如类似于 -ffast-math。 然后,翻译器可以插入任何额外的 wasm 修正,以将 nan 强制为所需的格式。 为此,我们可以提供 isNan 或 normalizeNan 运算符,尽管我现在不提倡这样做。

简而言之,最好将“修复”留给更高级别的工具 IMO。

+1 @mbodart。 编辑:哦,看,现在实际上有一个 +1 的东西:)。 顺便说一句,我个人认为 Wasm = 世界统治,因此未来的处理器不会对抗它。

我想在做出决定之前量化这对性能的影响。 我认为我们的工具链目前还太不成熟,无法进行良好的性能测量(在这个过程中有更长的极点)。 换句话说:我想避免“千刀万剐”。

我同意@jfbastien。 在修补语义之前,需要首先量化性能影响。

需要明确的是,我目前并不主张在这里进行更改。 我正在收集理由材料。 NaN 位不确定性突出,需要解释。 据我所知,也没有人量化使这些位不确定的性能影响。

当两个操作数都是 NaN 时,ARMv8 并不总是传播第一个操作数。 规则是:

  • 如果一个操作数是一个安静的 NaN 而另一个是一个信号 NaN,则传播信号 NaN。
  • 否则,传播第一个操作数。

在我阅读规范时,这适用于 ARMv8 的 Aarch32 和 Aarch64 模式。

这种行为不同于在两种情况下传播第一个操作数的 SSE。

两种架构都将通过在传播之前设置安静位将 sNaN 转换为 qNaN。

@stoklund好地方! 我错过了在第二个 NaN 发出信号的情况下,ARM 不会选择第一个 NaN。 这会使我为上述多个 NaN 情况制定的策略复杂化,因此我们可以在基本原理中提及这一点。

我现在创建了 #973 来提出总结上述内容的特定文本。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

artem-v-shamsutdinov picture artem-v-shamsutdinov  ·  6评论

arunetm picture arunetm  ·  7评论

chicoxyzzy picture chicoxyzzy  ·  5评论

konsoletyper picture konsoletyper  ·  6评论

dpw picture dpw  ·  3评论