我目前正在尝试深入学习浮点表示,所以我尝试了一下。这样做的时候,我偶然发现了一些奇怪的行为;我无法真正弄清楚发生了什么,非常感谢您提供一些见解。很抱歉,如果有人回答了这个问题,我发现很难用谷歌搜索!
#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 设置为可以使用以下方式表示的最小 float 单精度
- 除以 2 应该得到 0 -- 我们处于最小值
- 确实,isZero2 确实返回 true,但 isZero 返回 false。
这是怎么回事——我本以为它们是一样的?编译器是不是在耍小聪明,说任何数相除都不可能为零?
感谢您的帮助!
最佳答案
isZero
和 isZero2
可以计算出不同的值,并且 isZero
可以为假的原因是允许 C++ 编译器实现比表达式类型指示的精度更高的中间浮点运算,但必须在赋值时删除额外的精度。
通常,在为 387 历史 FPU 生成代码时,生成的指令要么在 80 位扩展精度类型上工作,要么,如果 FPU 设置为 53 位有效数(例如在 Windows 上),一个奇怪的具有 53 位尾数和 15 位指数的浮点类型。
无论哪种方式,minVal/2.0f
的计算都是因为指数范围允许表示它,但是将它分配给 nextCheck
会将其舍入为零。
如果你使用的是GCC,还有一个问题是-fexcess-precision=standard
还没有为C++前端实现,也就是说g++生成的代码没有实现正是标准所建议的。
关于c++ - 将类型转换 float 与零进行比较时的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26690196/