NAN传播和IEEE 754标准

12

我正在设计一个新的微处理器指令集 (www.forwardcom.info),想要使用NAN传播技术来跟踪错误。然而,IEEE 754浮点数标准中存在一些奇怪的问题阻止了这一进展。

首先,我想使用NAN传播而不是错误捕获的原因是我有可变长度的向量寄存器。例如,如果我有一个包含8个元素的float向量,并且第一个元素为1/0,第六个元素为0/0,则只会获取一个陷阱,但如果在半向量长度的计算机上运行相同的程序,则会获取两个陷阱:无穷大和NAN各一个。我希望结果与向量长度无关,因此需要依赖于NAN和INF的传播而不是捕获。 NAN和INF值将通过计算进行传播,以便在最终结果中可以进行检查。 NAN表示包含一些称为有效载荷的位,可用于关于错误来源的信息。

但是,IEEE 754浮点数标准存在两个问题,防止了NAN值的可靠传播。

第一个问题是不同有效载荷的两个NAN的组合仅得到其中一个值。例如,NAN1 + NAN2给出NAN1。这违反了基本原则a+b = b+a。编译器可以交换操作数,以便在不同的编译器或不同的优化选项下获得不同的结果。我更喜欢获取两个有效载荷的按位OR组合。如果每个错误条件都有一个位,则这将起作用,但如果有效载荷包含更复杂的信息(例如具有动态类型的语言中的NAN boxing),那么它就行不通了。标准委员会实际上讨论过OR解决方案(请参见http://grouper.ieee.org/groups/754/email/msg01094.html)。我不知道他们为什么拒绝了这个提案。

第二个问题是,如果输入中只有一个是NAN,则min和max函数不会传播NAN。换句话说,min(1,NAN) = 1。可靠的NAN传播当然需要使min(1,NAN)= NAN。我不知道标准为什么要这样做。
在名为ForwardCom的新微处理器系统中,我希望避免这些不幸的怪癖,并指定NAN1 + NAN2 = NAN1 | NAN2,以及min(1,NAN)= NAN。
现在是我的问题: 首先,我是否需要选项开关来在严格IEEE符合性和可靠的NAN传播之间进行切换?引用标准:
安静NaN应该通过实施者自行决定的方式提供从无效或不可用数据和结果继承的回顾式诊断信息。为了促进包含在NaN中的诊断信息的传播,应该尽可能多地保留那些信息在操作的NaN结果中。
请注意,标准在这里说“应该”,而在其他地方则是“必须”。这是否意味着我的偏差是可以接受的?
第二个问题: 我找不到任何实际使用NAN传播跟踪错误的示例。也许这是由于标准的弱点。例如,我想为不同的错误条件定义不同的有效负载位,例如:
0/0、0*∞、∞/∞、modulo(1,0)、modulo(∞,1)、∞-∞以及涉及无穷大和除以零的其他错误。 sqrt(-1)、log(-1)、pow(-1,0.1)以及由对数和幂导出的其他错误。 asin(2)和其他数学函数。 显式赋值。当一个变量被初始化为NAN时,这可能是有用的。
用户定义的错误代码有大量空位可用。
这样做过吗,还是我必须从头开始发明一切?我是否需要考虑其他问题(除了某些语言中的NAN盒装)

3
任何涉及NAN的比较都会返回false。即使x是NAN,x==x也会返回false。min(x,y)可以实现为min(x,y) = x < y ? x : y。如果任何一个输入为NAN,它将返回y,因此min(1,NAN) = NAN,min(NAN,1) = 1。这是不合逻辑的。我们期望min(x,y)和min(y,x)是相同的。 - A Fog
3
@NicolBolas:NaN 并不仅仅存在于记录无效操作的目的。某些用户使用 NaN 作为传递信息的有效载荷,IEEE 754 在制定标准时已经考虑到了这一点。 - Eric Postpischil
3
IEEE 754委员会通常不会把“拼写出来”的代码转化为“Intrinsic(内在函数)”。当然,该委员会的一个目标是以有益的方式标准化有用的操作。然而,在这种情况下,“拼写出来”的代码并不具有信息性,因为min可以由x<y?x:yx>y?y:x组成。这些代码对于x = 1,y = NaN将产生不同结果,选择其中一个结果将是任意的。如果该操作是可交换的,则更好,使它不会因计算顺序的变化而发生改变。 - Eric Postpischil
7
下一版IEEE 754标准的当前草案中包含既有偏向NaN的minimummaximum,也有偏向数值的minimumNumbermaximumNumber。这意味着一个应用程序可以选择适合自己的选项,但如果您希望其提供符合性,则指令集必须支持两种选项。 - Eric Postpischil
2
@AFog:工作草稿在这里(http://754r.ucbtest.org/drafts/)。 - Eric Postpischil
显示剩余11条评论
4个回答

6
是的,您可以偏离“应该”的规定。从规范(§1.6)中可以看出:
― “may”表示在标准范围内允许采取的行动,没有暗示的偏好(“may”表示“被允许”)
― “shall”表示必须严格遵循的强制性要求,不允许偏差(“shall”表示“被要求”)
― “should”表示在多种可能性中,推荐一种作为特别适合的,而不提及或排除其他;或者某种行动是首选但不一定需要的;或者(在否定形式中)某种行动被弃用但不被禁止(“should”表示“建议使用”)。
关于min的行为,英特尔实现也与IEEE规范不同。来自英特尔指令集参考的MINSD的说明如下:
如果第二个源操作数中的值为SNaN,则将SNaN不变地返回到目标(即不返回SNaN的QNaN版本)。
如果只有一个值为NaN(SNaN或QNaN),则将第二个源操作数(NaN或有效浮点值)写入结果。如果需要返回NaN源操作数(来自第一个或第二个源)而不是这种行为,则可以使用一系列指令来模拟MINSD,例如比较后跟AND、ANDN和OR。
换句话说,它对应于x < y ? x : y。(有关更多详细信息,请参见Argument order to std::min changes compiler output for floating-point:这是C++ std::min,而不是包装IEEE-754 NaN传播的C数学库fminminimum操作。)
实际上我不确定他们心目中的特定序列是什么,但在此处提出了一种替代方法:https://github.com/JuliaLang/julia/issues/7866#issuecomment-51845730

2
感谢提供 Julia 讨论的参考。它包含了许多相关观点。 - A Fog
非常愉快!感谢您在网站上提供的优秀资源,这些年来我发现它们非常有价值。 - Simon Byrne
对于习惯于使用C和/或x86术语的人来说,IEEE“minimum”(NaN传播)就像C数学库“fmin”。x86“minsd”等实现了C ++“std :: min”,两者都完全实现了“x <y?x:y”。std :: min的参数顺序更改会改变浮点编译器输出(因此minsd既不是IEEE“minimum”(NaN传播),也不是IEEE“minimumNumber”(如果任一操作数是数字,则取该数字),请参见@Eric的答案)。虽然minsd是某些东西的有用构建块,但无法使用单个minsd实现fmin - Peter Cordes

4

一些想法:

第二个问题是,如果仅有一个输入为NAN,则min和max函数不会传播NAN。换句话说,min(1, NAN) = 1。当然,可靠的NAN传播需要使min(1, NAN) = NAN。我不知道标准为什么会这样规定。

下一个IEEE 754修订草案包含了NaN优先的minimummaximum以及数字优先的minimumNumbermaximumNumber。这意味着应用程序可以选择适合自己的选项,但如果您打算提供符合性,那么您的指令集必须同时支持这两种选项。(请注意,“支持”而不是“实现”。指令集不需要直接在单独的指令中实现IEEE 754操作,以便使计算平台符合IEEE 754 - 它只需提供可以构建符合平台的指令即可。如果IEEE 754操作需要多个指令或来自操作系统或库的支持,则可以这样做。)

现在我的问题是:首先,我是否需要一个选项开关来在严格遵守IEEE和可靠的NAN传播之间进行切换?

由于返回的NaN只是标准中的“建议”,因此您不需要返回推荐的NaN来声明符合性。但是,minimum(1, NaN)必须返回NaN。

当然,您不必通过开关来实现该要求,由于环境状态会影响性能,因此不建议这样做。可以使用不同的指令或附带正常寄存器内容的附加寄存器或附加位来选择不同的行为。

第二个问题:我找不到任何实际使用NAN传播跟踪错误的示例。

我记得至少有一个IEEE 754委员会成员利用NaN有效载荷,但我不记得是谁或详情。


2
关于两个NaN的相加。当您将具有不同有效负载的两个NaN相加时,您只会得到其中一个,通常是第一个。这使得a + b与b + a不同,这是不可接受的,因为编译器可能会交换操作数。上面,我建议返回两个有效负载的按位OR组合。经过思考,还有另一种可能的解决方案:返回两个有效负载中最大的一个。
“OR”解决方案的优点是简单。缺点是它将有效负载中有用的信息限制为每个可能的错误条件的一位。尽管如此,它仍然非常有用,因为可以生成NaN的不同事件数量少于有效负载位数。
第二个解决方案,即返回两个有效负载中最大的一个,需要稍微多一些硬件。优点是您可以在有效负载中拥有更详细的信息,也许包括有关故障发生位置的信息。缺点是您只传播了两个故障中最糟糕的一个的信息。这个解决方案与当前标准完全兼容。新处理器可以实现此功能,而无需为向后兼容性而进行切换。

我喜欢返回最大有效载荷的想法,因为这样可以使其对称。然而,有些应用程序可能仍然更喜欢按位或,或者返回第一个(不对称)。也许它应该像舍入模式一样可配置。 - Yakov Galka

1
仅供讨论,IEEE标准明确允许在NaN中进行错误编码的灵活性,但指出这应由编程语言实现而不是在硬件层面上完成。 话虽如此:我确实喜欢支持硬件级别的位或语义的nan污染语义的观点。 我一直在探索将相同的语义添加到ghc Haskell编译器中。
话虽如此,我认为捕获语义/信号语义仍然很有用。 在许多编程语言/程序中,启用的陷阱集可以被视为底层计算中的异常中止。 这意味着报告一对还是两个错误的平台变化问题不会改变局部计算的“含义”。 (实际上,可以说许多高级编程语言将受益于支持将信号nan视为异常的处理。这似乎在很大程度上缺乏)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接