浮点表达式检查器

2021-07-24 15:58:16

以下工具可让您检查浮点表达式的计算流程,查看舍入发生的位置、触发异常的时间、可能丢失精度的时间、特殊值传播的时间、错误累积的时间以及其他令人头疼的浮点问题。 [fpinspect]# ./fpinspect "sqrt(45.0*e+phi)/pi"Exception: 0 (1 roundings) INEXACT (45.000000 * e) Trace (1 operation) MULException: 0 (1 roundings) INEXACT phi Trace (1 operation) ) MULException: 0 (2 roundings) INEXACT ((45.000000 * e) + phi)Exception: 1 (2 roundings) INEXACT ((45.000000 * e) + phi) Trace (2 operation) MUL ADDException: 0 (3 roundings) INEXACT sqrt (((45.000000 * e) + phi))例外:1(3 舍入)不精确的 sqrt(((45.000000 * e) + phi))例外:2(3 舍入)不精确的 sqrt(((45.000000 * e) + phi) ) 跟踪(3 次操作)MUL ADD ADDException:0(3 次舍入)不正确的 piException:1(3 次舍入)不正确的 piException:2(3 次舍入)不正确的 pi 跟踪(3 次操作)MUL ADD ADDException:0(4 次舍入)不正确(sqrt) (((45.000000 * e) + phi)) / pi)例外:1(4 舍入)不准确(sqrt(((45.000000 * e)+ phi))/pi)例外:2(4 舍入)不准确(sqrt((() (45.000000 * e) + phi))) / pi)例外:3 (4 舍入) INEXACT (sqrt(((45.000000 * e) + phi)) / pi) Trace (4 operation) ns) MUL ADD ADD DIV(sqrt(((45.000000 * e) + phi))) / pi) ans: 3.54370117187500 err: 0.00000126456894 如您所见,表达式 sqrt(45.0*e+ pi) 产生了大量的输出,每个空行分隔的区域都是一个触发异常的子表达式,在这种情况下,因为 45 * e 是一个不精确的值,首先呈现不精确的异常。在这里你可以看到这样的表达式涉及 1 个操作,total,在这种情况下,操作只是一个 MUL。我们还可以看到结果表达式,因为它不精确,导致了一个舍入。沿着异常列表向下,我们可以看到异常传播到 MUL 中的 phi(这也是一个不精确的值),并继续,每个新的不精确子表达式导致多次舍入。由于像 sqrt 这样的内核本身可能会使用像 add 这样的操作,我们还看到最后一组异常在它的跟踪中包含一个额外的 ADD。表达式的最终结果在 ans: 中给出,下面你会发现计算该表达式的累积误差 err:,在这种情况下,这个函数精确到五个尾数位,总共七位,这意味着这个表达式有~0.71 ULP 错误。该程序完全在软件中实现 IEEE-754 浮点,模拟所有舍入模式、异常和微小检测方法,这些方法可以在评估表达式时进行配置。除超越函数外,所有浮点计算也精确到 <= 1 ULP 的误差。目前支持 32 位单精度浮点 float32.{h,c} 和 64 位双精度浮点 float64.{h,c},因为 32 位单精度需要双精度精度内核 kernel32.{h,c} 以产生正确舍入和截断的结果<= 1 ULP 的错误。

目前没有 64 位内核,因为这需要在软件中实现 80 位双精度浮点或 128 位四精度浮点,以具有产生正确舍入和截断结果所需的精度< = 1 ULP 错误。