Prolog lib(ic)的精确解

Prolog lib(ic)的精确解,prolog,floating-accuracy,eclipse-clp,interval-arithmetic,clpr,Prolog,Floating Accuracy,Eclipse Clp,Interval Arithmetic,Clpr,使用EclipseProlog,我偶然发现了下面的问题,我被。事实上,这只是其中的一部分。首先,让我用(is)/2来表示方程。此外,请注意,所有这些十进制数字都以基数2浮点数(包括IEEE)精确表示: 所以这实际上是0.0(根本没有舍入)。但是现在用$=代替的方法是: [eclipse 3]: X= -1, Y = 2, Null $= 0.80143857*X+1.65707065*Y-2.51270273. X = -1 Y = 2 Null = 2.2204460492503131e-1

使用EclipseProlog,我偶然发现了下面的问题,我被。事实上,这只是其中的一部分。首先,让我用
(is)/2
来表示方程。此外,请注意,所有这些十进制数字都以基数2浮点数(包括IEEE)精确表示:

所以这实际上是0.0(根本没有舍入)。但是现在用
$=
代替
的方法是

[eclipse 3]: X= -1, Y = 2, Null $= 0.80143857*X+1.65707065*Y-2.51270273.

X = -1
Y = 2
Null = 2.2204460492503131e-16__2.2204460492503131e-16
Yes (0.00s cpu)
此间隔不包含0.0。我知道区间算术通常有点过于近似,如:

[eclipse 4]: 1 $= sqrt(1).

Delayed goals:
    0 $= -1.1102230246251565e-16__2.2204460492503131e-16
Yes (0.00s cpu)
但至少等式成立!然而,在第一种情况下,不再包括零。显然我还不明白什么。我也尝试了
eval/1
,但没有成功

[eclipse 5]: X= -1, Y = 2, Null $= eval(0.80143857*X+1.65707065*Y-2.51270273).

X = -1
Y = 2
Null = 2.2204460492503131e-16__2.2204460492503131e-16
Yes (0.00s cpu)
Null
不包括
0.0
的原因是什么


(在@jsf令人惊讶的回答之后编辑)

这是书中187页的引文,我认为这意味着数字是准确的(现在被划过)

使用{3,5}环境,可以模拟IEEE单精度的环境。输入值完全可以表示
{-1,2}
完成了这项工作,用少于所用位的一半计算出准确答案

否则,第184页的声明将:

0.80143857 x+1.65707065 y=2.51270273

这些方程式看起来确实很简单。假设精确的十进制输入,这个系统由x=-1和y=2精确求解

这是用SICStus的
库(clpq)
重新检查的:

所以-1,2是精确解


精确的公式 这是一个在输入系数中没有舍入问题的重新公式,但解决方案仍然是简单的-∞...+∞. 因此,这是微不足道的正确,但不可用

[eclipse 2]: A = 25510582, B = 52746197, U = 79981812, 
C = 80143857, D = 165707065, V = 251270273,
A*X+B*Y$=U,C*X+D*Y$=V.

A = 25510582
B = 52746197
U = 79981812
C = 80143857
D = 165707065
V = 251270273
X = X{-1.0Inf .. 1.0Inf}
Y = Y{-1.0Inf .. 1.0Inf}


Delayed goals:
    52746197 * Y{-1.0Inf .. 1.0Inf} + 25510582 * X{-1.0Inf .. 1.0Inf} $= 79981812
    80143857 * X{-1.0Inf .. 1.0Inf} + 165707065 * Y{-1.0Inf .. 1.0Inf} $= 251270273
Yes (0.00s cpu)

这里有几个问题共同造成了混乱:

  • 除了声明之外,示例中的三个常量 没有双浮点数的精确表示

  • 最初的例子不涉及四舍五入,这是不对的

  • 第一个例子中看似正确的结果实际上是由于 幸运的四舍五入误差。其他计算顺序给出不同的结果

  • 精确结果,给出了 这些常数实际上不是零而是2.2204460492503131e-16

  • 区间算法只能在输入 是准确的,这里不是这样。常数必须是 加宽为包含所需小数的区间

  • 像lib(ic)所提供的关系算术本质上就是这样的 不保证特定的评估顺序。因此,四舍五入 错误可能与功能评估期间遇到的错误不同。 然而,对于给定常数,结果将是准确的

  • 下面将更详细地介绍。正如我将展示的 使用ECLiPSe查询的要点,提前简单介绍一下语法:

    • 由双下划线分隔的两个浮点,例如
      0.99\uu 1.01
      在这种情况下,表示具有下限和上限的区间常数 1附近的数字

    • 由一个下划线分隔的两个整数,例如
      3\u 4
      用分子和分母表示有理常数 案例四分之三

    要演示点(1),请转换的浮点表示形式 将0.80143857转换为有理数。这给出了精确的分数 3609358445212343/4503599627370496,接近但不相同, 到预定的小数点80143857/100000000。浮点 因此,表述不准确:

    下面显示了结果如何取决于评估顺序 (上文第3点;请注意,我已将原始示例简化为 去掉不相关的乘法):

    顺序相关性证明存在舍入误差(第2点)。对于那些熟悉浮点运算的人来说,事实上很容易看出这一点 添加
    -0.80143857+3.3141413
    时,
    0.80143857
    在调整操作数的指数时丢失。事实上是这样 这个幸运的四舍五入错误给了OP一个看似正确的结果

    在现实中,第二个结果相对于 常量的浮点表示形式。我们可以证明这一点 通过使用精确的有理运算重复计算:

    ?- 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)
    
    由于加法是用精确的有理数完成的,所以结果现在是正确的 订单独立,因为
    14503599627370496=:=2.2204460492503131e-16
    , 这确认了上面获得的非零浮点结果(第4点)

    区间算术在这里有什么帮助?它通过使用 包含真实值的间隔,这样结果将始终 输入数据要准确。因此,至关重要的是 输入间隔(ECLiPSe术语中的有界实数),包含 所需的真实值。这些可以通过书写它们来获得 明确向下,例如
    0.80143856_uu0.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)
    
    这两个结果现在都包含零,很明显
    结果的精度取决于求值顺序。

    因此,直接浮点值不应解释为精确值,而应解释为来自十进制表示的间隔。目前,间隔的语法也会受到舍入的影响,因此这是一个固有的问题:
    writeq(1.0000000000000000000000002_uu1.0000000000000000003)。1.0_uu1.0
    。相反,应该有一个
    代表
    
    ?- F is rational(0.80143857), F =\= 80143857_100000000.
    F = 3609358445212343_4503599627370496
    Yes (0.00s cpu)
    
    ?- 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)
    
    ?- 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)
    
    ?- 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)