1

在 GCC 9.1 中,当使用浮点类型调用 std::numeric_limits 的函数时,它们在大多数情况下返回 0。

这发生在我正在处理的项目中,MSVC、GCC 8.3 或 Clang 8.0 没有问题。<double>::epsilon()有时具有正确的值,但是当从其他文件调用时,它也可能评估为 0。

// Commented values at the end of the lines are the values given by the debugger
// Making the variable constexpr doesn't change their values

auto intMax = std::numeric_limits<int>::max(); // {int} 2147483647

auto floatMax     = std::numeric_limits<float>::max();     // {float} 0
auto floatEpsilon = std::numeric_limits<float>::epsilon(); // {float} 0
auto floatMin     = std::numeric_limits<float>::min();     // {float} 0
auto floatLowest  = std::numeric_limits<float>::lowest();  // {float} -0

auto doubleMax     = std::numeric_limits<double>::max();     // {double} 0
auto doubleEpsilon = std::numeric_limits<double>::epsilon(); // {double} 2.2204460492503131e-16
auto doubleMin     = std::numeric_limits<double>::min();     // {double} 0
auto doubleLowest  = std::numeric_limits<double>::lowest();  // {double} -0

std::cout << std::setprecision(10) << std::fixed
          << "Max int        = " << std::numeric_limits<int>::max()
          << "\n"
          << "\nMax float      = " << std::numeric_limits<float>::max()
          << "\nEpsilon float  = " << std::numeric_limits<float>::epsilon()
          << "\nMin float      = " << std::numeric_limits<float>::min()
          << "\nLowest float   = " << std::numeric_limits<float>::lowest()
          << "\n"
          << "\nMax double     = " << std::numeric_limits<double>::max()
          << "\nEpsilon double = " << std::numeric_limits<double>::epsilon()
          << "\nMin double     = " << std::numeric_limits<double>::min()
          << "\nLowest double  = " << std::numeric_limits<double>::lowest() << std::endl;

<int>::max()此处留作参考)

产生一个独立的文件(正确的值):

Max int        = 2147483647

Max float      = 3.40282e+38
Epsilon float  = 1.19209e-07
Min float      = 1.17549e-38
Lowest float   = -3.40282e+38

Max double     = 1.79769e+308
Epsilon double = 2.22045e-16
Min double     = 2.22507e-308
Lowest double  = -1.79769e+308

项目结果:

Max int        = 2147483647

Max float      = 0
Epsilon float  = 0
Min float      = 0
Lowest float   = -0

Max double     = 0
Epsilon double = 2.22045e-16
Min double     = 0
Lowest double  = -0

独立编译专用文件时,这些值是正确的:问题不是来自 GCC(正如我所料),但很可能来自项目的配置。

编辑:独立编译项目文件(目前出现此问题)也可以提供正确的结果。随着gcc -dM -E__DBL_MAX__被定义为double(1.79769313486231570814527423731704357e+308L)

__DBL_MAX__值被定义,被 ifdef 包围的代码被执行:

#ifdef __DBL_MAX__
#pragma message "__DBL_MAX__ defined"
#endif

/*
note: #pragma message: __DBL_MAX__ defined
   40 | #pragma message "__DBL_MAX__ defined"
      |                 ^~~~~~~~~~~~~~~~~~~~~
*/

GDB 给出了相同的精确值,所以输出部分没有问题。输出XXX_YYY__XXX_YYY__给出相同的结果,因为 numeric_limits 的函数无论如何都会调用它们。

100%明确:std::numeric_limits<double>::max() == 0返回true,所以输出部分没有问题。它只是留在这里作为参考。

GCC 产生这种行为的原因可能是什么?反正不是__XXX_YYY__内置值吗?他们怎么可能持有0?

4

1 回答 1

1

所以错误来自(至少间接地)预编译的头文件,我们将其与 cotire 一起用于 CMake。

这些标题包含的每个文件,手动单独包含在“有问题的”文件中,都没有重现该问题。

虽然有点奇怪,但除了 cotire 之外,我没有看到任何可行的解释。根据这个线程,显然已经报告了限制问题:C++ Cmake build with cotire and gtest - error with float.h

临时解决方案是禁用 GCC 9.1+ 的预编译头文件。如果有人遇到过同样的问题,如果您知道为什么以及如何发生这种情况,请随时添加评论或答案。

感谢 Giovanni、Kamil 和 nm 在评论中引导我走向正确的方向!

于 2019-07-17T13:05:56.250 回答