今天,我在看一些c++代码(别人写的),发现了这一部分:
double someValue = ...
if (someValue < std::numeric_limits<double>::epsilon() &&
someValue > -std::numeric_limits<double>::epsilon()) {
someValue = 0.0;
}
我在想这到底说得通不合理。
epsilon()的文档说:
该函数返回1与可[用双精度符号]表示的大于1的最小值之间的差值。
这是否也适用于0,即()的最小值大于0?或者有没有0到0 +之间的数可以用双精度数表示?
如果不是,那么比较是不是等同于someValue == 0.0?
X和X的下一个值之间的差值根据X而变化。
Epsilon()只是1和下一个1的值之间的差。
0和下一个0值之间的差不是()。
相反,你可以使用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;
}
X和X的下一个值之间的差值根据X而变化。
Epsilon()只是1和下一个1的值之间的差。
0和下一个0值之间的差不是()。
相反,你可以使用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;
}
假设我们正在使用适合16位寄存器的玩具浮点数。有一个符号位,一个5位指数和一个10位尾数。
这个浮点数的值是尾数,解释为二进制十进制值,乘以2的指数次方。
在1附近,指数等于0。尾数中最小的数字是1024的1分之一。
接近1/2的指数是- 1,所以尾数最小的部分是一半大。如果是5位指数,它可以达到负16,此时尾数最小的部分值为3200万分之一。在- 16指数处,这个值大约是32k的1分之1,比我们上面计算的1附近更接近于0 !
这是一个玩具式的浮点模型,它不能反映真正的浮点系统的所有怪癖,但是它反映小于的值的能力与真正的浮点值相当相似。