为什么Octave比0'更早?

问题描述 投票:6回答:1

Context:

在Octave中,我编写了一个Sigmoid函数的代码,该函数返回0到1之间的值;在一个理想的世界中,它只会为-Inf返回0而对于+ Inf只返回1,但由于浮点不精确,非常接近这些值的值都是四舍五入的。

The Question:

我的问题是为什么会发生以下情况:对于0和1,舍入的边界明显不同:

>> sigmoid(-709)
ans =   1.2168e-308
>> sigmoid(-710)
ans = 0
>> sigmoid(36)
ans =  1.00000
>> sigmoid(37)
ans =  1
>> (sigmoid(37)-1)==0
ans = 1
>> (sigmoid(36)-1)==0
ans = 0
>> sigmoid(-710)==0
ans = 1
>> sigmoid(-709)==0
ans = 0

在这个例子中,我们可以看到将输出舍入为1所需的值在数量上要小于舍入到0所需的值.37与-710相比是一个非常大的差异,因为它们的幅度应该相同但是相反的迹象......

My Code:

也许这是我的功能问题:

function [z] = sigmoid(x)
z = 1.0 ./(1.0+exp(-x));
endfunction

What I've Tried:

另一点是,我改变了函数,将结果加1(基本上将图形翻译为1),边界分别变为+/- 37,分别为2和1 - 这让我觉得它真的与0有关特别是,而不仅仅是功能及其下限。

如果它与我的电脑有关,那会是什么导致这样的事情?

floating-point octave rounding data-representation
1个回答
9
投票

首先,回顾this brilliant answer by gnovice on floating-point representation

有了这个,让我们来看看你在这里看到的东西:你可以计算一个非常接近于零的值:sigmoid(-709)大约等于1.2e-308,但是你不能计算一个类似接近于1的值:sigmoid(709)完全等于1,而不是1 - 1.2e-308,甚至sigmoid(36) == 1,而不是略小于1的值。

但是当我们知道浮点数如何存储在内存中时,我们会发现1 - 1.2e-308无法准确表示。我们需要308个十进制数字来准确表示这个数字。双精度浮点数(Octave中的默认值)大约有15个十进制数字。也就是说,1 - 1e-16可以代表,但1 - 1e-17不能。

eps(1)的值是2.2204e-16,这是我们可以在双精度浮点数中编码的最小差值。

但接近0的值可以更精确地表示:eps(0)4.9407e-324。这是因为像1.2e-308这样的值不需要表示308个十进制数字,而只需要表示2,指数中的值为-308。

在任何情况下,如果您依赖于远离过渡位置的sigmoid函数的精确值,那么您的代码逻辑就会出现问题。

如果你想使这个函数对称,你所能做的就是降低低端的精度。有两种方法可以做到这一点:

  1. 只需设置为零非常小的值,以便在另一侧与z==0相同的点达到z==1function z = sigmoid(x) z = 1.0 ./ (1.0+exp(-x)); z(z < eps(1)) = 0; end
  2. 始终计算功能的右半部分,然后折回以获得负输入。这使得x=0两侧的计算误差对称: function z = sigmoid(x) z = 1.0 ./ (1.0+exp(-abs(x))); I = x < 0; z(I) = 0.5 - z(I); end
© www.soinside.com 2019 - 2024. All rights reserved.