NAN传播和IEEE 754标准

时间:2018-02-27 14:45:28

标签: c++ floating-point nan ieee-754

我正在设计一个新的微处理器指令集(www.forwardcom.info),我想使用NAN传播来跟踪错误。但是,IEEE 754浮点标准中存在许多阻止这种情况的奇怪现象。

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

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

第一个问题是两个具有不同有效载荷的NAN的组合只是两个值中的一个。例如,NAN1 + NAN2给出NAN1。这违反了a + b = b + a的基本原则。编译器可以交换操作数,以便在不同的编译器或不同的优化选项上获得不同的结果。我更喜欢得到两个有效载荷的按位OR组合。如果每个错误条件都有一位,那么这将起作用,但当然,如果有效负载包含更复杂的信息(例如具有动态类型的语言中的NAN装箱),则无效。标准委员会实际上讨论了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传播之间进行切换?引用标准:

  

安静的NaNs应该由实施者自行决定提供继承的回顾性诊断信息   来自无效或不可用的数据和结果。促进包含的诊断信息的传播   在NaNs中,尽可能多的信息应该保存在NaN运算结果中。

请注意,标准说"应该"在这里,它有"将"别处。这是否意味着我允许偏离建议?

第二个问题: 我找不到实际使用NAN传播来跟踪错误的任何示例。也许这是因为标准的弱点。我想为不同的错误条件定义不同的有效负载位,例如:

  1. 0 / 0,0 *∞,∞/∞,模数(1,0),模数(∞,1),∞-∞,以及涉及无穷大和除零的其他误差。

  2. sqrt(-1),log(-1),pow(-1,0.1)以及其他来自对数和幂的错误。

  3. asin(2)和其他数学函数。

  4. 明确分配。当变量初始化为NAN时,这可能很有用。

  5. 用户定义的错误代码有很多空位。

    之前是否已经完成,或者我是否必须从头开始创造一切?有什么问题我必须考虑(除了某些语言的NAN拳击)

4 个答案:

答案 0 :(得分:4)

是的,你被允许偏离“应该”。从规范(§1.6):

  

- 可能表示在标准范围内允许的行动方式,没有隐含的偏好(“可能”表示“允许”)

     

- 表示严格遵守强制性要求,以符合标准,且不允许偏离(“应”表示“需要”)

     

- 应该表示在多种可能性中,建议特别适合一种,不提及或排除其他可能性;或者某种行动方案是首选但不一定是必需的;或者(以否定的形式)某种行为被弃用但不被禁止(“应该”的意思是“建议”)。

关于min的行为,英特尔的实施也与IEEE规范不同。来自MINSD的英特尔指令集参考:

  

如果第二个源操作数中的值是SNaN,则SNaN将不变地返回到目标(即,   不返回QNaN版本的SNaN。

     

如果此指令只有一个值是NaN(SNaN或QNaN),则第二个源操作数,NaN或有效值   浮点值,写入结果。如果不是这种行为,则需要NaN源操作数   (从第一个或第二个源)返回,MINSD的动作可以使用一系列的模拟   指令,例如,比较后跟AND,ANDN和OR。

换句话说,它对应于x < y ? x : y。我实际上并不确定它们的具体顺序是什么,但这里提出了另一种方法https://github.com/JuliaLang/julia/issues/7866#issuecomment-51845730

答案 1 :(得分:2)

一些想法:

  

第二个问题是,如果只有一个输入是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 :(得分:0)

关于添加两个NAN。当您添加两个具有不同有效负载的NAN时,您只需获得其中一个,通常是第一个。这使得a + b与b + a不同,这是不可接受的,因为编译器可以交换操作数。上面,我建议返回两个有效负载的按位OR组合。考虑到这一点,还有另一种可能的解决方案:返回两个有效载荷中最大的一个。

'OR'解决方案的优点是它很简单。缺点是它会将有效负载中的有用信息限制为每个可能的错误条件一位。但是,它仍然非常有用,因为可以生成NaN的不同事件的数量小于有效载荷比特的数量。

返回两个有效负载中最大的有效负载的第二个解决方案需要稍多的硬件。优点是您可以在有效负载中获得更详细的信息,可能包括有关故障发生位置的信息。缺点是您只传播有关两个最差故障的信息。该解决方案与当前标准完全兼容。新的处理器可以实现这一点而无需向后兼容的开关。

答案 3 :(得分:0)

为了补充这一讨论,ieee标准明确允许Nan中的错误编码灵活性,但表明它是通过编程语言实现而不是在硬件层完成的。这就是说:我确实喜欢在硬件级别上使用按位或语义支持纳米中毒语义的观点。我一直在探索将这个相同的语义添加到ghc Haskell编译器中。

尽管如此,我确实认为捕获语义/信令语义仍然有用。在许多编程语言/程序中,启用的陷阱集可以被视为基础计算中的中止异常。这意味着平台变化的问题是,串联报告一对二错误是不会改变本地计算的“含义”。 (事实上​​可以说,很多高级编程语言都会受益于支持将信令nans视为异常。这似乎很大程度上缺乏)