今天,我一直在寻找通过一些C ++代码(由别人写的),发现本节:
double someValue = ...
if (someValue < std::numeric_limits<double>::epsilon() &&
someValue > -std::numeric_limits<double>::epsilon()) {
someValue = 0.0;
}
我想弄清楚这是否甚至是有道理的。
对于文档epsilon()
说:
该函数返回[通过双] 1和最小的大于1的值即可表示之间的差。
这是否适用于0为好,即epsilon()
是最小的值大于0? 或者有没有之间的数字0
和0 + epsilon
可以由代表double
?
如果不是,那么是不是等同于比较someValue == 0.0
?
Answer 1:
假设64位IEEE双,有一个52位尾数和11位指数。 让我们来打破它位:
1.0000 00000000 00000000 00000000 00000000 00000000 00000000 × 2^0 = 1
最小可表示数大于1:
1.0000 00000000 00000000 00000000 00000000 00000000 00000001 × 2^0 = 1 + 2^-52
因此:
epsilon = (1 + 2^-52) - 1 = 2^-52
是否有0型和戊型之间的任意数字? 大量...如最小正表示的(普通)号码为:
1.0000 00000000 00000000 00000000 00000000 00000000 00000000 × 2^-1022 = 2^-1022
事实上,有(1022 - 52 + 1)×2^52 = 4372995238176751616
0和ε,这是所有正表示数的47%之间的数...
Answer 2:
测试肯定是不一样的someValue == 0
。 浮点数的整体思路是,它们存储指数和尾数。 因此,它们代表具有(在IEEE双的情况下53)一定数目的精度的二进制数字显著的值。 该表示的值更密集接近0比接近1。
要使用更熟悉的十进制,假设你存储一个数值“4级显著人物”与指数。 然后下一个可表示值大于1
是1.001 * 10^0
,和epsilon
是1.000 * 10^-3
。 不过1.000 * 10^-4
也可表示,假设指数可以存储-4。 你可以把我的话是比指数更低的IEEE双CAN店指数epsilon
。
你不能从这个代码单独告诉它是否有道理,还是不要用epsilon
专门为界,你需要看看上下文。 这可能是因为epsilon
是在所产生的计算误差的合理估计someValue
,并且它可以是它不是。
Answer 3:
有迹象表明,0和小量之间存在因为小量是1之间,并且可以在上面1表示下一个最高数和不为0之间的差值,并且可以大于0来表示(如果它是下一个最大的数目的差数,即代码会很少做): -
#include <limits>
int main ()
{
struct Doubles
{
double one;
double epsilon;
double half_epsilon;
} values;
values.one = 1.0;
values.epsilon = std::numeric_limits<double>::epsilon();
values.half_epsilon = values.epsilon / 2.0;
}
在主要结束使用调试器,停止该程序并查看结果,你会发现小量/ 2为ε,零和一个截然不同的。
因此,该功能只+/-小量之间的值,使它们为零。
Answer 4:
围绕一个数字(1.0,0.0,...)的ε-的aproximation(最小可能差)可以被印有下面的程序。 它打印的输出如下:
epsilon for 0.0 is 4.940656e-324
epsilon for 1.0 is 2.220446e-16
小算盘清楚,即小量变小的更小的数字是我们用来查看其小量价值,因为该指数能适应这个数字的大小。
#include <stdio.h>
#include <assert.h>
double getEps (double m) {
double approx=1.0;
double lastApprox=0.0;
while (m+approx!=m) {
lastApprox=approx;
approx/=2.0;
}
assert (lastApprox!=0);
return lastApprox;
}
int main () {
printf ("epsilon for 0.0 is %e\n", getEps (0.0));
printf ("epsilon for 1.0 is %e\n", getEps (1.0));
return 0;
}
Answer 5:
假设我们正在与适合在一个16位的寄存器玩具浮点数工作。 有一个符号位,5位指数和10位尾数。
这浮点数的值是尾数,解释为一个二进制十进制值,时间的两个给幂的。
大约1的指数等于零。 所以尾数的最小数字是在1024的一部分。
近1/2的指数是负一,所以尾数的最小部分的一半。 有了一个5位的指数可以达到负16,在这一点尾数的最小部分是值得32米一个组成部分。 而在负16指数,该值是围绕一个部分在32K,比一个绕小量我们上面计算更接近于零!
现在,这是一个玩具浮点模型,并不能反映真实的浮点系统的所有怪癖,而是要体现价值比小量小的能力与实际浮点值相当类似。
Answer 6:
之间的差X
和的下一个值X
而变化,根据X
。
epsilon()
是仅之间的差1
和的下一个值1
。
之间的差0
和的下一个值0
不epsilon()
相反,你可以使用std::nextafter
与之比较的双精度值0
,如下所示:
bool same(double a, double b)
{
return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b
&& std::nextafter(a, std::numeric_limits<double>::max()) >= b;
}
double someValue = ...
if (same (someValue, 0.0)) {
someValue = 0.0;
}
Answer 7:
我认为这取决于精确您的计算机。 就这个一看表 :你可以看到,如果你的小量由双表示,但你的精度更高,比较不等同于
someValue == 0.0
好问题呢!
Answer 8:
您不能将此应用到0,因为尾数和指数部分。 由于指数可以存储非常少的数字,这比小量小,但是当你试图做类似(1.0 - “极少数”),你会得到1.0。 小量为不值的指标,但值的精度,这是在尾数。 它展示了许多许多正确随之而来的十进制数字,我们可以存储。
Answer 9:
所以我们说系统不能区分1.000000000000000000000和1.000000000000000000001。 即1.0和1.0 + 1E-20。 你觉得还有是可以-1e-20和+ 1E-20之间代表的一些价值观?
Answer 10:
与IEEE浮点,最小非零正值和最小非零负值之间,存在两个值:正零和负零。 测试一个值是否是最小的非零值之间相当于测试与零的相等; 分配,但是,可能有效果,因为它会改变一个负零到正零。
这将能想到,一个浮点格式可能具有最小的有限的正负值之间的三个值:正无穷,无符号零和负无穷。 我不熟悉任何浮点格式,其实工作的方式,但是这样的行为是完全合理的,可以说是比IEEE(更好的也许不够好,值得增加额外的硬件来支持它,但数学1 /(1 / INF),1 /( - 1 / INF)和1 /(1-1)应该表示三种不同的情况示出了三个不同的零)。 我不知道任何C标准是否将要求签署无穷,如果存在,就不得不比较等于零。 如果他们不这样做,像上面的代码可以有效保证如反复划分数由两个最终产量为零,而不是停留在“无穷小”。
Answer 11:
此外,一个很好的原因具有这样的功能是消除“非规格化”(那些非常小的数字,可以不再使用隐含的前导“1”,并有专门的FP表示)。 你为什么想做这个? 由于某些机器(尤其是一些老的Pentium 4)得到真正的,非正规处理时很慢。 其他人只是拿到有点慢。 如果您的应用程序并不真正需要这些非常小的数字,他们冲洗至零是一个很好的解决方案。 好的地方考虑这是任何IIR滤波器或衰减函数的最后一个步骤。
另请参阅: 为什么改变0.1F到了10倍,0降低性能?
和http://en.wikipedia.org/wiki/Denormal_number
文章来源: Compare double to zero using epsilon