📅 2015-Jan-05 ⬩ ✍️ Ashwin Nanjappa ⬩ 🏷️ cpp, error, math ⬩ 📚 Archive
Math functions provided by the standard C++ library are defined in the cmath
header file. Many of these functions require their input values to be in a specific domain. For example, the log
function requires its input to be greater than zero. log(-3.14)
or log(0)
is not defined mathematically. The result of such a call is set to a special NaN
, inf
or -inf
value. However, no exception is thrown and the call has actually failed silently. Note that this does not affect the correctness of future math function calls.
There is no warning option provided by GCC that can be enabled to detect such errors in the code. Nor is there any compiler option to enable the standard C++ library to thrown an exception, say std::domain_error
, when such an error occurs. Other libraries, like Boost, do throw such exceptions.
The only way to prevent these math errors is to check the bounds of the inputs passed to these functions. For example, you can write a wrapper function for each of such math functions that does the bounds checking and throws error or exception when the input is wrong. You can change your code to explicitly use only these math wrapper functions instead of those from cmath
.
If the performance of this math code is important to you, then inline this function and enable the bounds checking only in Debug mode or when you want to check the correctness of some inputs. Disable the checking for Release mode.
When a math function is executed with wrong input, the errno
variable from the cerrno
header file is set to non-zero value. The list of error values can be seen here. Specifically, for math errors, it might be set to either ERANGE
or EDOM
. This refers to a range or domain error respectively. To get the error string explaining the error, use the std::strerror
function.
For example:
// Checking for math error in C++
#include <cerrno>
#include <cmath>
#include <cstring>
#include <iostream>
std::cout << log(0) << std::endl;
if (errno)
std::cout << std::strerror(errno) << std::endl;
if (errno == EDOM)
std::cout << "Domain error\n";
if (errno == ERANGE)
std::cout << "Range error\n";
Reference: Section 40.3, The C++ Programming Language (4 Ed) by Stroustrup
Tried with: GCC 4.9.2 and Ubuntu 14.04