今天,我在看一些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?


当前回答

该测试当然与someValue == 0不同。浮点数的全部思想是存储一个指数和一个显著值。因此,它们表示具有一定数量的精度二进制有效位数的值(在IEEE双精度的情况下为53)。可表示值在0附近比在1附近密集得多。

为了使用更熟悉的十进制系统,假设您使用exponent存储一个“4位有效数字”的十进制值。那么下一个大于1的可表示值是1.001 * 10^0,是1.000 * 10^ 3。但是1.000 * 10^-4也是可以表示的,假设指数可以存储-4。你可以相信我的话,IEEE double可以存储小于的指数。

你不能仅仅从这段代码中判断用作为边界是否有意义,你需要看一下上下文。可能是对产生someValue的计算错误的合理估计,也可能不是。

其他回答

可以用下面的程序输出一个数(1.0,0.0,…)的近似值(可能的最小差值)。输出如下: 0.0 = 4.940656e-324 1.0的是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;
}

我认为这取决于你电脑的精度。 看一下这张表:你可以看到,如果用double表示,但你的精度更高,比较并不等于

someValue == 0.0

不管怎样,这是个好问题!

假设系统无法区分1.000000000000000000000和1.00000000000000001。这是1.0和1.0 + 1e-20。你认为在-1e-20和+1e-20之间还有一些值可以表示吗?

Also, a good reason for having such a function is to remove "denormals" (those very small numbers that can no longer use the implied leading "1" and have a special FP representation). Why would you want to do this? Because some machines (in particular, some older Pentium 4s) get really, really slow when processing denormals. Others just get somewhat slower. If your application doesn't really need these very small numbers, flushing them to zero is a good solution. Good places to consider this are the last steps of any IIR filters or decay functions.

请参见:为什么将0.1f更改为0会使性能降低10倍?

和http://en.wikipedia.org/wiki/Denormal_number

你不能把这个应用到0,因为有尾数和指数部分。 由于指数可以存储很小的数,小于, 但是当你尝试做一些类似(1.0 -“非常小的数字”)的事情时,你会得到1.0。 Epsilon不是值的指示器,而是值精度的指示器,值精度是尾数。 它显示了我们可以存储多少个正确的十进制数字。