我正在设计一个新的微处理器指令集(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 . 这违反了b = b a的基本原则 . 编译器可以交换操作数,以便在不同的编译器或不同的优化选项上获得不同的结果 . 我更喜欢得到两个有效载荷的按位OR组合 . 如果每个错误条件都有一位,那么这将起作用,但当然,如果有效负载包含更复杂的信息(例如具有动态类型的语言中的NAN装箱),则无效 . 标准委员会实际上讨论了OR'ing解决方案(见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 *∞,∞/∞,模(1,0),模(∞,1),∞-∞,以及涉及无穷大和除零的其他误差 .
-
sqrt(-1),log(-1),pow(-1,0.1)以及从对数和幂导出的其他错误 .
-
asin(2)等数学函数 .
-
明确赋值 . 当变量初始化为NAN时,这可能很有用 .
用户定义的错误代码有很多空位 .
这是否已经完成,或者我是否必须从零开始创造一切?我有什么问题需要考虑(除了某些语言的NAN拳击)
4 回答
是的,你被允许偏离“应该” . 从规范(§1.6):
关于
min
的行为,英特尔的实现也与IEEE规范不同 . 来自MINSD
的英特尔指令集参考:换句话说,它对应于
x < y ? x : y
. 我实际上并不确定它们的特定顺序是什么,但是这里有一种替代方法https://github.com/JuliaLang/julia/issues/7866#issuecomment-51845730 .一些想法:
下一个IEEE 754修订版的当前草案包含NaN-favoring
minimum
和maximum
以及number-favoringminimumNumber
和maximumNumber
. 这意味着应用程序可以选择适合它的内容,但是如果您打算提供一致性,那么您的指令集必须支持两者 . (注意“支持”而不是“实现” . 指令集不需要在单个指令中直接实现IEEE 754操作,以使计算平台符合IEEE 754 - 它只需要提供符合平台的指令如果IEEE 754操作需要来自操作系统或库的多个指令或支持,则可以构建 . )由于您返回的NaN只是标准中的“应该”,因此您无需返回推荐的NaN来声明一致性 . 但是,
minimum(1, NaN)
必须返回NaN .当然,您不必通过开关来做到这一点,并且环境状态由于其性能拖累而不受欢迎 . 可以通过附加寄存器或伴随正常寄存器内容的附加位,利用指令的不同指令或不同输入来完成行为之间的选择 .
我记得至少有一个IEEE 754委员会成员利用NaN有效载荷,但我不记得是谁或细节 .
关于添加两个NAN . 当您添加两个具有不同有效负载的NAN时,您只需获得其中一个,通常是第一个 . 这使得b与b不同,这是不可接受的,因为编译器可以交换操作数 . 上面,我建议返回两个有效负载的按位OR组合 . 考虑到这一点,还有另一种可能的解决方案:返回两个有效载荷中最大的一个 .
'OR'解决方案的优点是它很简单 . 缺点是它会将有效负载中的有用信息限制为每个可能的错误条件一位 . 但是,它仍然非常有用,因为可以生成NaN的不同事件的数量小于有效载荷比特的数量 .
返回两个有效载荷中最大的有效载荷的第二个解决方案需要稍多的硬件 . 优点是您可以在有效负载中获得更详细的信息,可能包括有关故障发生位置的信息 . 缺点是您只传播有关两个最差故障的信息 . 该解决方案与当前标准完全兼容 . 新的处理器可以实现这一点而无需向后兼容的开关 .
为了补充这一讨论,ieee标准明确允许Nan中的错误编码灵活性,但表明它是通过编程语言实现而不是在硬件层完成的 . 这就是说:我确实喜欢在硬件级别上使用按位或语义支持纳米中毒语义的观点 . 我一直在探索将这个相同的语义添加到ghc Haskell编译器中 .
那就是说,我确实认为捕获语义/信令语义仍然有用 . 在许多编程语言/程序中,启用的陷阱集可以被视为基础计算中的中止异常 . 这意味着平台变化的问题是,串联报告一对二错误是不会改变本地计算的“含义” . (事实上可以说,许多高级编程语言都会受益于支持将信令nans视为异常 . 这似乎很大程度上缺乏)