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

Time:12-14

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.

CodePudding user response:

I'm going to take a stab in the dark and guess you are enabling fast-math in your build?

Without fast-math:

https://godbolt.org/z/vMo1P7Mn1

With fast-math:

https://godbolt.org/z/jEsGz7n38

The error handling within cmath tends to break things like vectorisation & constexpr (setting external global variables, is a side effect that breaks both cases). As a result, you are usually better off checking for domain errors yourself...

CodePudding user response:

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.

  • Related