c++ - 将类型转换 float 与零进行比较时的奇怪行为

标签 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 设置为可以使用以下方式表示的最小 float 单精度
  • 除以 2 应该得到 0 -- 我们处于最小值
  • 确实,isZero2 确实返回 true,但 isZero 返回 false。

这是怎么回事——我本以为它们是一样的?编译器是不是在耍小聪明,说任何数相除都不可能为零?

感谢您的帮助!

最佳答案

isZeroisZero2 可以计算出不同的值,并且 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/

相关文章:

c++ - Eclipse IDE,正则表达式搜索和替换

c++ - 编译文件时无法在ubuntu上找到一些boost库

c++ - 在 Windows 上默认启用 GCC 编译器 C++11 标志

c - c中是否有固定大小为两个字节的浮点类型?

c++ - 客观内存比较

arrays - 快速比较数组

c++ - 解析文本文件时抛出 std::out_of_range

actionscript-3 - 将十六进制字符串转换为单精度 ActionScript 3.0

c++ - 为什么除法(?)会产生这个数字?

java - 线程中的异常 "AWT-EventQueue-0"java.lang.IllegalArgumentException : Comparison method violates its general contract