我目前正在尝试深入了解浮点表示,所以我玩了一下。在这样做的时候,我偶然发现了一些奇怪的行为;我无法确定正在发生的事情,我会非常感激一些见解。如果有人回答道歉,我发现谷歌很难!
#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;
}
基本上发生的事情是:
发生了什么 - 我会认为它们是相同的?编译器是否试图变得聪明,说除了任何数字都不可能产生零?
感谢您的帮助!
答案 0 :(得分:5)
isZero
和isZero2
可以评估为不同值的原因,isZero
可能为false,是允许C ++编译器实现中间浮点运算的精度高于表达式的类型将指示,但必须在赋值时删除额外的精度。
通常,在为387历史FPU生成代码时,生成的指令适用于80位扩展精度类型,或者,如果FPU设置为53位有效数字(例如,在Windows上),则为奇怪的具有53位有效数字和15位指数的浮点类型。
无论哪种方式,都会对minVal/2.0f
进行精确计算,因为指数范围允许表示它,但将其指定给nextCheck
会将其舍入为零。
如果您正在使用GCC,则还存在{C}前端尚未实现-fexcess-precision=standard
的问题,这意味着g ++生成的代码并未完全实现标准推荐的内容。