Math_errhandling not working as expected with nvc++ compiler

Hello everyone,

I came across math_errhandling in MATH_ERRNO, MATH_ERREXCEPT, math_errhandling - cppreference.com and I was trying to run the example code of standard library math functions mentioned in cppreference.com that uses the math error handling however I noticed that even if MATH_ERRNO is enabled in nvc++ it is not working properly.
Starting from the example presented in std::sqrt, std::sqrtf, std::sqrtl - cppreference.com I wrote the following code:

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cfenv>
#include <cstring>

#pragma STDC FENV_ACCESS ON

int main()
{
    // normal use
    std::cout << "sqrt(100) = " << std::sqrt(100) << '\n'
              << "sqrt(2) = " << std::sqrt(2) << '\n'
              << "golden ratio = " << (1+std::sqrt(5))/2 << '\n';
    // special values
    std::cout << "sqrt(-0) = " << std::sqrt(-0.0) << '\n';
    // error handling
    errno = 0;
    const auto errno_enabled = math_errhandling & MATH_ERRNO;
    const auto check_fe_except = math_errhandling & MATH_ERREXCEPT;
    std::cout << "errno_enabled: " << errno_enabled << " check_fe_except: " << check_fe_except << std::endl;
    std::feclearexcept(FE_ALL_EXCEPT);
    double d = std::sqrt(-1);
    std::cout << "sqrt(-1.0) = " << d << '\n';
    std::cout << "    errno = " << errno << " " << std::strerror(errno) << '\n';
    if(errno == EDOM)
        std::cout << "    errno = EDOM " << std::strerror(errno) << '\n';
    if(std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

Compiling the above code with nvc++ I get the following output:

$ nvc++ ../t_sqrt.cpp -o t_sqrt_nvc++         
"../t_sqrt.cpp", line 7: warning: unrecognized STDC pragma
  #pragma STDC FENV_ACCESS ON
               ^
$ ./t_sqrt_nvc++                     
sqrt(100) = 10
sqrt(2) = 1.41421
golden ratio = 1.61803
sqrt(-0) = 0
errno_enabled: 1 check_fe_except: 2
sqrt(-1.0) = -nan
    errno = 0 Success
    FE_INVALID raised

I’m using NVHPC 22.3 and I’m testing this on linux 20.04.
The above output suggests to me that while errno should be set to EDOM it is not set properly. Instead only the FE_INVALID is set.
Is there any way to enable the update of the errno variable in such cases or is there some other issue that this variable is not set to the ERRNO value?
Compiling the same code with nvcc returns the expected output:

$ nvcc ../t_sqrt.cpp -o t_sqrt_nvcc
$ ./t_sqrt_nvcc 
sqrt(100) = 10
sqrt(2) = 1.41421
golden ratio = 1.61803
sqrt(-0) = -0
errno_enabled: 1 check_fe_except: 2
sqrt(-1.0) = -nan
    errno = 33 Numerical argument out of domain
    errno = EDOM Numerical argument out of domain
    FE_INVALID raised

Thank you very much in advance for your time.

1 Like

Hi iomagkanaris,

By default, sqrt gets inlined into a single ‘vsqrt’ instruction which is much better for performance. If you do need the error handling support, please add the flag “-Mnobuiltin” so the library sqrt is used. It’s much slower, but will set errno.

% nvc++ -Mnobuiltin test.cpp ; a.out
"test.cpp", line 7: warning: unrecognized STDC pragma
  #pragma STDC FENV_ACCESS ON
               ^

sqrt(100) = 10
sqrt(2) = 1.41421
golden ratio = 1.61803
sqrt(-0) = -0
errno_enabled: 1 check_fe_except: 2
sqrt(-1.0) = -nan
    errno = 33 Numerical argument out of domain
    errno = EDOM Numerical argument out of domain
    FE_INVALID raised

Note that nvcc is using g++ as the host compiler which defaults to this slower version of sqrt. Adding g++'s “-ffast-math” flag will give the same result as our default:

% nvcc test.cpp -Xcompiler  -ffast-math ; a.out
sqrt(100) = 10
sqrt(2) = 1.41421
golden ratio = 1.61803
sqrt(-0) = -0
errno_enabled: 0 check_fe_except: 0
sqrt(-1.0) = -nan
    errno = 0 Success
    FE_INVALID raised

Hope this clarifies things,
Mat

Dear Mat,

Thanks a lot for the quick reply and explanations. I managed to reproduce the behaviour you mentioned.
Is it safe to presume that floating point exceptions like FE_INVALID will be generated in such cases or should there be any other flag set in the nvc++ compiler?
Thank you very much again in advance for your answer.

Kind regards,
Ioannis

Is it safe to presume that floating point exceptions like FE_INVALID will be generated in such cases or should there be any other flag set in the nvc++ compiler?

It’s my understanding that the vsrqt instruction will produce Invalid Operation or Inexact exceptions. It just doesn’t set errno.

Great. Thank you very much for your replies!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.