将浮点数与零进行比较的标准方法是什么?

klm*_*123 4 c++ floating-point

可疑问题是:将浮点数与零进行比较的标准方法是什么?

据我所知直接比较:

if ( x == 0 ) { 
  // x is zero?
} else {
  // x is not zero??
Run Code Online (Sandbox Code Playgroud)

可以使用浮点变量失败.

我以前用过

float x = ...
...
if ( std::abs(x) <= 1e-7f ) { 
  // x is zero, do the job1
} else {
 // x is not zero, do the job2
...
Run Code Online (Sandbox Code Playgroud)

我在这里找到相同的方法.但我看到两个问题:

  1. 随机幻数1e-7f(或上面链接的0.00005).
  2. 代码更难阅读

这是一个常见的比较,我想知道是否有一个标准的简短方法来做到这一点.喜欢

 x.is_zero();
Run Code Online (Sandbox Code Playgroud)

Pet*_*ker 5

要将浮点值与 0 进行比较,只需比较它:

if (f == 0)
    // whatever
Run Code Online (Sandbox Code Playgroud)

这种比较没有任何问题。如果它没有按照你的预期运行,那是因为它的价值f不是你想象的那样。它本质上与此相同的问题:

int i = 1/3;
i *= 3;
if (i == 1)
    // whatever
Run Code Online (Sandbox Code Playgroud)

这种比较并没有错,但 的值i不是 1。几乎所有程序员都理解整数值的精度损失;许多人不理解浮点值。

使用“几乎相等”代替==是一种高级技术;它经常导致意想不到的问题。例如,它不是可传递的;也就是说,a几乎等于bb几乎等于c意味着a几乎等于c

  • @Phlip - 你是对的,它不像整数截断那样清晰和明显(尽管对于许多初学者来说,整数截断是**不**明显的;见证 StackExchange 上的问题数量,答案是“你正在做整数数学;将其更改为浮点数”)。尽管如此,**本质上** 是同一个问题,解决方案是了解为什么您的数字不是您期望的那样,并相应地修改您的期望。不幸的是,编程课程一般不会很好地教授浮点数,结果是程序员害怕它。 (4认同)
  • @Phlip:不,程序员在使用浮点数时应该了解错误的来源,并设计具有适当容差的算法。 (3认同)
  • @Phlip:不,浮点数具有明确定义的语义。将浮点视为“不可预测”,因为您懒得理解它不是要走的路。 (3认同)
  • @Phlip - 你有什么建议作为替代方案?如果有人不理解浮点数学,添加更多他们不理解的东西(例如“几乎相等”)会使情况变得更糟。如果您认为浮点数学是不可预测的,则意味着您对它的了解不足以使用它。在这种情况下,在您对它有更多了解之前不要使用它。 (3认同)
  • @SteveJessop:“除非溢出,整数算术是准确的”不是一个真实的陈述。当 5% 的年利率转换为月利率时,整数运算会得到错误的答案。即使没有溢出,整数算术也不是关联的。即使将美元换算为便士,正如 Stack Overflow 的许多答案所建议的那样,当产品价格乘以销售税率时,整数算法会得到错误的四舍五入答案。 (3认同)

Ste*_*sop 5

没有标准的方法,因为你是否想要将一个小数字视为零,取决于你如何计算数字和它的用途.这又取决于计算引入的任何误差的预期大小,也可能取决于确定原始输入的物理测量误差.

例如,假设您的值表示某些地图软件中的行程长度(以英里为单位).那么你很乐意将它1e-7视为等于零,因为在这种情况下它是一个非常小的数字:它是由于舍入误差或其他轻微不精确的原因而产生的.

另一方面,假设您的值代表某些电子显微镜软件中分子的大小(以米为单位).那么你当然希望1e-7等同于零,因为在那种情况下它是一个非常大的数字.

您应该首先考虑什么是合适的准确度来呈现您的价值:什么是误差条,或者您可以合理地显示多少有效数字.这将让你对使用什么样的容差进行测试,以便对零进行测试,尽管它仍然可能无法解决问题.对于地图软件,如果旅程小于某个固定值,您可以将旅程视为零,尽管该值本身可能取决于地图的分辨率.对于显微镜软件,如果两个尺寸之间的差别在于零在于这些测量的95%的误差范围内,仍然可能足够来形容他们为相同的大小.