c++gccnumeric-limitsgcc9

__FLT_MAX__ and __DBL_MAX__ to 0?


With GCC 9.1, when calling std::numeric_limits's functions with floating-point types, they return 0 in most cases.

This happens in a project I'm working on, and there is no issue with MSVC, GCC 8.3 or Clang 8.0. <double>::epsilon() sometimes has a correct value, but when called from other files it may evaluate to 0 as well.

// 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;

(The <int>::max() is left as a reference here)

Result in an independent file (correct values):

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

Result in the project:

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

When compiling a dedicated file indepentenly, the values are correct: the issue is then not from GCC (as I expected anyway), but most likely from the project's configuration.

EDIT: compiling a project's file (on which this issue occurs at the moment) independently gives correct results as well. With gcc -dM -E, the __DBL_MAX__ is defined to double(1.79769313486231570814527423731704357e+308L).

The __DBL_MAX__ value is defined, code surrounded by an ifdef is executed:

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

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

GDB gives the same exact value, so no problem on the output part. Outputting XXX_YYY or __XXX_YYY__ gives the same results, since numeric_limits' functions call them anyway.

To be 100% clear: std::numeric_limits<double>::max() == 0 returns true, so there is no problem on the output part. It is just left here as a reference.

What could be the reason(s) GCC produces such behavior? Aren't __XXX_YYY__ built-in values anyway? How can they possibly hold 0?


Solution

  • So the error came from (at least indirectly) the precompiled headers, which we use with cotire for CMake.

    Every file included by those headers, manually included individually in the "problematic" files, did not reproduce the issue.

    Although a bit weird, I don't see any viable explanation other than cotire for now. It has apparently already been reported to have problems with limits, as per this thread: C++ Cmake build with cotire and gtest - error with float.h

    The temporary solution will then be to disable precompiled headers with GCC 9.1+. If anyone has had the same kind of issue, feel free to add comments or answers if you do know why and how this happens.

    Thanks to Giovanni, Kamil and n.m in the comments who led me in the right direction!