c++errnocmath

errno doesn't change after putting a negative value in sqrt()


With errno, I am trying to check if cmath functions produce a valid result. But even after I put a negative value in sqrt() or log(), errno stays at value 0. Can anyone know why, and how I can make errno behave correctly?

The environment is macOS Monterey version 12.6.1, the compiler is gcc version 11.3.0 (Homebrew GCC 11.3.0_1) or Apple clang version 14.0.0 (clang-1400.0.29.202) (I tried the 2 compilers). The compile command is g++ test_errno.cpp -o test_errno -std=c++14.

The piece of code I tried is directly copied from this page. The following is the code.

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <clocale>
 
int main()
{
    double not_a_number = std::log(-1.0);
    std::cout << not_a_number << '\n';
    if (errno == EDOM) {
        std::cout << "log(-1) failed: " << std::strerror(errno) << '\n';
        std::setlocale(LC_MESSAGES, "de_DE.utf8");
        std::cout << "Or, in German, " << std::strerror(errno) << '\n';
    }
}

Its result didn't print the error messages, which should be printed if errno is set correctly.


Solution

  • It seems that on macOS, errno is not used, from this bug report from @GAVD's comment. I could check that via math_errhandling value from @Pete Becker's comment. It seems there are 2 ways of math error handling in C/C++, either with errno, or with floating-point exception, as the 2nd link above shows. We can check which way (or both of them) the system's math library employs, via checking if macro constant math_errhandling is equal to MATH_ERREXCEPT or MATH_ERRNO, like the following (copied from the 2nd link):

        std::cout << "MATH_ERRNO is "
                  << (math_errhandling & MATH_ERRNO ? "set" : "not set") << '\n'
                  << "MATH_ERREXCEPT is "
                  << (math_errhandling & MATH_ERREXCEPT ? "set" : "not set") << '\n';
    

    And on my system, the output is

    MATH_ERRNO is not set
    MATH_ERREXCEPT is set
    

    , which means the system does not use errno for reporting math errors, but use floating-point exception. That's why errno stays at value 0 no matter what, and I should have used std::fetestexcept() to check error conditions. With floating-point exceptions, std::feclearexcept(FE_ALL_EXCEPT); corresponds to errno = 0;, and std::fetestexcept(FE_DIVBYZERO) corresponds to errno == ERANGE for example.