将cast float与零比较时的奇怪行为

时间:2014-11-01 14:28:21

标签: c++ floating-point comparison

我目前正在尝试深入了解浮点表示,所以我玩了一下。在这样做的时候,我偶然发现了一些奇怪的行为;我无法确定正在发生的事情,我会非常感激一些见解。如果有人回答道歉,我发现谷歌很难!

#include <iostream>
#include <cmath>
using namespace std;

int main(){

  float minVal = pow(2,-149); // set to smallest float possible
  
  float nextCheck = static_cast<float>(minVal/2.0f); // divide by two
  bool isZero = (static_cast<float>(minVal/2.0f) == 0.0f); // this evaluates to false
  bool isZero2 = (nextCheck == 0.0f); // this evaluates to true
  cout << nextCheck << " " << isZero << " " << isZero2 << endl;
  // this outputs 0 0 1
  
  return 0;

}

基本上发生的事情是:

  • 我将minVal设置为可以使用的最小浮点数 单精度
  • 除以2应该得到0 - 我们处于最低
  • 的确,isZero2确实返回true,但isZero返回false。

发生了什么 - 我会认为它们是相同的?编译器是否试图变得聪明,说除了任何数字都不可能产生零?

感谢您的帮助!

1 个答案:

答案 0 :(得分:5)

isZeroisZero2可以评估为不同值的原因,isZero可能为false,是允许C ++编译器实现中间浮点运算的精度高于表达式的类型将指示,但必须在赋值时删除额外的精度。

通常,在为387历史FPU生成代码时,生成的指令适用于80位扩展精度类型,或者,如果FPU设置为53位有效数字(例如,在Windows上),则为奇怪的具有53位有效数字和15位指数的浮点类型。

无论哪种方式,都会对minVal/2.0f进行精确计算,因为指数范围允许表示它,但将其指定给nextCheck会将其舍入为零。

如果您正在使用GCC,则还存在{C}前端尚未实现-fexcess-precision=standard的问题,这意味着g ++生成的代码并未完全实现标准推荐的内容。