答案 0 :(得分:5)
这里有几个问题合谋造成混淆:
示例中的三个常量 不具有双重浮动的精确表示。
初始示例不涉及舍入是不正确的。
第一个例子中看似正确的结果实际上是由于a 幸运的舍入错误。其他计算订单会产生不同的结果。
确切的结果,给出最近的双浮点表示 常数,确实不是零,但2.2204460492503131e-16。
区间运算只能在输入时给出准确的结果 是准确的,这不是这里的情况。常数必须是 扩大到包含所需小数的间隔。
lib(ic)提供的关系算法本质上就是这样 不保证特定的评估订单。因此四舍五入 错误可能与功能评估期间遇到的错误不同。 然而,结果对于给定的常数是准确的。
以下更详细介绍。正如我将展示一些 使用ECLiPSe查询点,预先快速了解语法:
由双下划线分隔的两个浮点数,例如0.99__1.01
在这种情况下,表示具有下限和上限的区间常数
1附近的数字。
由单个下划线分隔的两个整数,例如3_4
用这个表示分子和分母的有理常数
案例四分之三。
要演示point(1),请转换float的表示形式 成为理性的0.80143857。这给出了精确的分数 3609358445212343/4503599627370496,虽然很近但并不完全相同, 到预期的小数部分80143857/100000000。浮点 因此,表示不确切:
?- F is rational(0.80143857), F =\= 80143857_100000000.
F = 3609358445212343_4503599627370496
Yes (0.00s cpu)
以下显示结果如何取决于评估顺序 (上面的第3点;请注意我已将原始示例简化为 摆脱无关的乘法):
?- Null is -0.80143857 + 3.3141413 - 2.51270273.
Null = 0.0
Yes (0.00s cpu)
?- Null is -2.51270273 + 3.3141413 - 0.80143857.
Null = 2.2204460492503131e-16
Yes (0.00s cpu)
顺序依赖性证明了出现舍入误差(第2点)。对于那些熟悉浮点运算的人来说,事实上很容易看出来
添加-0.80143857 + 3.3141413
时,来自0.80143857
的两位精度
在调整操作数的指数时迷路。事实上它是
这个幸运的舍入错误给了他看似正确的结果!
实际上,第二个结果更准确 常量的浮点表示。我们可以证明这一点 通过使用精确的有理算术重复计算:
?- Null is rational(-0.80143857) + rational(3.3141413) - rational(2.51270273).
Null = 1_4503599627370496
Yes (0.00s cpu)
?- Null is rational(-2.51270273) + rational(3.3141413) - rational(0.80143857).
Null = 1_4503599627370496
Yes (0.00s cpu)
由于添加是以精确的理性完成的,现在的结果是
与订单无关,因为1_4503599627370496 =:= 2.2204460492503131e-16
,
这证实了上面得到的非零浮点结果(第4点)。
区间运算如何帮助?它通过计算工作
包含真值的间隔,以便始终得到结果
对输入是准确的。因此,拥有它至关重要
包含的输入间隔(ECLiPSe术语中的有界实数)
期望的真实价值。这些可以通过编写它们来获得
明确地,例如0.80143856__0.80143858
;
通过从精确数字转换,例如合理使用
breal(80143857_100000000)
;或者通过自动指示解析器
将所有浮点数加宽到有界实数区间,如下所示:
?- set_flag(syntax_option, read_floats_as_breals).
Yes (0.00s cpu)
?- Null is -0.80143857 + 3.3141413 - 2.51270273.
Null = -8.8817841970012523e-16__1.3322676295501878e-15
Yes (0.00s cpu)
?- Null is -2.51270273 + 3.3141413 - 0.80143857.
Null = -7.7715611723760958e-16__1.2212453270876722e-15
Yes (0.00s cpu)
这两个结果现在都包含零,并且它变得明显如何 结果的精确度取决于评估顺序。