为什么是经验( ln( x ) ) − x ≠ 0exp⁡(ln⁡(x))−x≠0在浮点运算中?

计算科学 浮点 精确
2021-12-06 12:53:48

解析,表达式

exp(ln(x))x,

应该给0。

但是,在 Matlab 中,它没有。

x = linspace(1, 10, 10);
exp(log(x)) - x;

对于,答案是x[1,10]

0   
0   
-4.44089209850063e-16   
0   
0   
0   
0   
-1.77635683940025e-15   
1.77635683940025e-15    
1.77635683940025e-15

发生了什么,我该如何解决这个问题?

4个回答

数值精度并不完美。在计算过程中会出现舍入错误。使用浮点数时,不要检查它们是否 = 0,而是检查它们到 0 的绝对距离是否小于某个 epsilon。

[编辑] 另一种观点:64 位浮点数表示离散集要使函数完全可逆,它应该是从的双射。假设我们对像这样快速增长的函数感兴趣。在某一时刻,如果中的最大元素,则严格版本是不允许的,因为SfSSexpexpx>xMSf(M)Mf(M)>MMS. 从道德上讲,像有限集上的双射一样的单调函数是一个排列,并且具有非常有限的自由度,它可能仅限于恒等式,或者是反转集合中元素顺序的反恒等式. 在这些琐碎的例子之外,单调函数不能是双射。

在实践中,这是由于有限精度的数值计算(例如64-bit浮点),尤其会影响涉及无理数的函数。整数或二次幂和的计算可能不太敏感。如果你敢于绘制数值误差,你会得到类似的东西: 数值误差平面

Matlab代码

x=linspace(1,10000,10000);
y = exp(log(x))-x;
plot(x,y,'.');
xlabel('x');
ylabel('y');

所以你可以看到最大误差随着值的传播。如果你想做某事,你可以检查和限制一个相对误差,特别是如果你的变量分布在一个很大的范围内。

更奇怪的是,如果你只是交换函数,比如:,在这种情况下,错误的数值为零。log(exp(x))x

x=linspace(1,700,10000);
y = log(exp(x))-x;
plot(x,y,'.');
xlabel('x');
ylabel('y');

在此处输入图像描述

基本问题是通常在使用固定精度浮点格式时。由于pidgeonhole 原理,这与计算指数函数和对数函数的精度无关exp(ln(x))x

在不失一般性的情况下,通过将二进制对数log2与 IEEE-754 二进制浮点格式之一结合使用,最容易证明这种效果。使用这种格式,每个二进制文件都包含相同数量的编码。如果我们计算log2两个连续的binade所有结果都将落入单个binade中。由于可用的源编码是目标编码的两倍,因此根据 pidgeonhole 原理,我们必须有大量的冲突。[4,8)[8,16)[2,4)

所有对数都是收缩运算。这意味着当使用固定精度浮点计算时,多个输入可以映射到同一个输出。由于这种压缩,信息会丢失,因此,当我们将中的数字扩展回,对于许多,即使两个函数都正确使用了全面实施。[2,4)[4,16)exp2x

颠倒操作顺序,即使用扩展操作后跟收缩逆操作,我们有时可以保证每个操作数往返成功,只要没有中间溢出或下溢,并假设正确舍入操作。我不知道(副手)这是否保证,但Laurent Duval 的回答中的图表似乎暗示了这一点。本文表明,的平方根恰好是xln(exp(x))=xx|x|

如果您有符号工具箱,您可以通过以下方式解决问题

syms x
y = exp(log(x))-x
% y = 0