正确处理 ISO-Prolog 中的非正规浮点数

Proper handling of denormal floats in ISO-Prolog

非正规浮点数一些特别的东西:

ISO-Prolog 标准如何处理这些问题?

我很清楚,每当这些异常发生时引发 evaluation_error(underflow) 异常 处理它们的正确方法,但这会产生额外的成本——每个浮动生产必须检查。

但是许多处理器提供的“将非正规数清零”(FTZ) 和“将非正规数视为零”(DAZ) 操作模式又如何呢? Prolog 实现可以使用这些吗?如果可以,他们如何正确地做到这一点?

是否 (1) 记录了这些操作模式的使用,(2) 确保非正规化被刷新为相同符号的零 (FTZ),以及 (3) 确保非正规化被视为相同符号的零(DAZ)够了吗?请帮忙!

不要跳过它们。然而,来自 ISO/IEC 13211-1:1995 9.1.4.2 浮点结果函数的简短回答:

It shall be implementation defined whether a processor
chooses round(x) or underflow when 0 < |x| < fminN.

但首先,我们称它们为次正规。过时的(至少根据 LIA 1:2012)概念 denormal(回想起来)不是很有帮助,因为它暗示了一些 de-viant、de-structive 属性。不:它们并不像你建议的那样特别。要看到这一点,请考虑实数的数轴。可以精确表示的数字被标记出来,并且在接近零(从两边)时彼此越来越接近。次正规是最接近零的那些。它们与零之间的距离与最小正规数之间的距离相同。那是他们的异常(或者可以说是异常)。如果你现在删除那些次正规,你会得到一个巨大的差距,导致更多的数值异常。这就像你在一把尺子上刮掉零旁边的标记,然后用这把破尺子来测量1。因此,在没有次正规的情况下,剩余的数字并不像人们可能认为的那样正常,而是异常的,容易出现更多错误。

如果您不喜欢阅读关于我仍然建议的主题的 Kahan,我可以推荐您阅读 Gustafson 的错误的结尾,它比我对次正规的解释要好得多。

在 13211-1 中,有可能排除次正规,但这只是为了与非常 RISCy、过时的架构兼容。

正式的一致性就到此为止。从长远来看,一些 Unum-style、CLP(BNR)-esque、Prolog IV-ish 方法可能很有前途。


1) 也就是说,如果您四舍五入为零。如果您生成 exceptions/continuation 值而不是更好的数值属性,只要不发生此类异常,就会保持不变。

在第 7.1.3 节中,ISO-Prolog 标准将集合 F 定义为您选择的 floating-point 格式可以表示的数字集合。此集合可能包含也可能不包含非规范化值,两种选择都是允许的。

当计算结果(绝对)大于零且小于最小归一化值时,您可以选择

  • 舍入为 F
  • 中可表示的值
  • 引发下溢异常

根据第 9.1.4.2 节,此选择是实现定义的,即您必须记录它。

这是一个小测试用例,用于查看您的 Prolog 系统是否可以 return 作为算术结果的次正规(没有清零,~FTZ):

/* SWI-Prolog */
?- X is 2.2250738585072011e-308 - 2.2250738585072012e-308.
X = -5.0e-324.
/* Jekejeke Prolog */
?- X is 2.2250738585072011e-308 - 2.2250738585072012e-308.
X = -4.9E-324

这是 API 中的新增功能,在 Prolog 系统中不一样,显示了次正规的参数传递(没有非正规零,~DAZ):

/* SWI-Prolog */
?- X is 2.2250738585072011e-308 - 2.2250738585072012e-308, 
float_parts(X,M,B,E).
X = -5.0e-324,
M = -0.5,
B = 2,
E = -1073.
/* Jekejeke Prolog */
?- X is 2.2250738585072011e-308 - 2.2250738585072012e-308, 
sys_float_mantissa(X,M), sys_float_exponent(X,E), sys_float_radix(X,R).
X = -4.9E-324,
M = -1,
E = -1074,
R = 2

结果来自 MacBook Air 2019。