Zac*_*c G 6 floating-point rounding octave data-representation
在Octave中,我编写了一个Sigmoid函数的代码,该函数返回0到1之间的值; 在一个理想的世界中,它只会为-Inf返回0而对于+ Inf只返回1,但由于浮点不精确,非常接近这些值的值都是四舍五入的.
我的问题是为什么会发生以下情况:对于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
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我们可以看到将输出舍入到1所需的值在数量上要小于舍入到0所需的值.37与-710相比是一个非常大的差异,因为它们的大小应该相同但是相反的迹象......
也许这是我的功能问题:
function [z] = sigmoid(x)
z = 1.0 ./(1.0+exp(-x));
endfunction
Run Code Online (Sandbox Code Playgroud)
另一点是,我改变了函数,将结果加1(基本上将图形翻译为1),边界分别变为+/- 37,分别为2和1 - 这让我觉得它真的与0有关特别是,而不仅仅是功能及其下限.
如果它与我的电脑有关,那会是什么导致这样的事情?
首先,回顾gnovice关于浮点表示的这个精彩答案.
有了这个,让我们来看看你在这里看到的东西:你可以计算一个非常接近于零的值: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)is 的值2.2204e-16,这是我们可以在双精度浮点数中编码的最小差值.
但接近0的值可以更精确地表示:eps(0)是4.9407e-324.这是因为一个值,例如1.2e-308不需要表示308个十进制数字,但只有2,指数中的值为-308.
在任何情况下,如果您依赖于远离过渡位置的sigmoid函数的精确值,那么您的代码逻辑就会出现问题.
如果你想使这个函数对称,你所能做的就是降低低端的精度.有两种方法可以做到这一点:
只需设置为零非常小的值,以便在与另一侧z==0相同的点z==1上达到:
function z = sigmoid(x)
z = 1.0 ./ (1.0+exp(-x));
z(z < eps(1)) = 0;
end
Run Code Online (Sandbox Code Playgroud)始终计算功能的右半部分,然后折回以获得负输入.这使得x=0对称的两侧的计算错误:
function z = sigmoid(x)
z = 1.0 ./ (1.0+exp(-abs(x)));
I = x < 0;
z(I) = 0.5 - z(I);
end
Run Code Online (Sandbox Code Playgroud)