...
The following table lists standard mathematical functions, along with checks that should be performed to ensure a proper input domain, and indicates whether they can also result in range or pole errors, as reported by the C Standard. If a function has a specific domain over which it is defined, the programmer must check its input values. The programmer must also check for range errors, where they might occur. The standard math functions not listed in this table, such as atanfabs()
, have no domain restrictions and cannot result in range or pole errors.
Function | Domain | Range | Pole |
---|---|---|---|
|
| No | No |
asin (x) | -1 <= x && x <= 1 | Yes | No |
atan (x) | None | Yes | No |
|
| No | No |
|
| Yes | No |
asin (x) | None | Yes | No |
|
| NoYes | Yes |
None | Yes | No | |
| None | Yes | No |
| None | Yes | No |
|
| No | Yes |
|
| No | Yes |
|
| Yes | No |
logb(x) | x != 0 | Yes | Yes |
| None | Yes | No |
| None | Yes | No |
| Yes | Yes | |
| No | No | |
erf (x) | None | Yes | No |
| None | Yes | No |
|
| Yes | Yes |
| None | Yes | No |
|
| NoYes | No |
| None | Yes | No |
| None | Yes | No |
| None | Yes | No |
...
See FLP03-C. Detect and handle floating-point errors for more details on how to detect floating-point errors.
Anchor | ||||
---|---|---|---|---|
|
Noncompliant Code Example (sqrt()
)
This noncompliant code example determines the square root of x
:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h>
void func(double x) {
double result;
result = sqrt(x);
} |
However, this code may produce a domain error if x
is negative.
Compliant Solution (sqrt()
)
Because this function has domain errors but no range errors, bounds checking can be used to prevent domain errors:
Denormal Arguments
Certain functions may produce range errors specifically when applied with a denormal argument. These functions are:
Function |
---|
asin(denorm) |
asinh(denorm) |
atan(denorm) |
atanh(denorm) |
erf(denorm) |
These functions when evaluated with a denormal argument can produce an inexact,denormal value, which is an underflow error. Subclause 7.12.1, paragraph 6, of the C Standard [ISO/IEC 9899:2011] defines the following behavior for floating-point underflow:
The result underflows if the magnitude of the mathematical result is so small that the mathematical result cannot be represented, without extraordinary roundoff error, in an object of the specified type. If the result underflows, the function returns an implementation-defined value whose magnitude is no greater than the smallest normalized positive number in the specified type; if the integer expression math_errhandling & MATH_ERRNO is nonzero, whether errno acquires the value ERANGE is implementation-defined; if the integer expression math_errhandling & MATH_ERREXCEPT is nonzero, whether the ‘‘underflow’’ floating-point exception is raised is implementation-defined.
Specifically, for implementations that support Annex F but do not support denormalized numbers, the following functions and arguments will cause range errors.
Function | Arguments |
---|---|
fmod() | ((min+denorm),min) |
remainder() | ((min+denorm),min) |
remquo() | ((min+denorm),min,quo) |
If denormal results are supported, the returned value is exact and there will not be a range error. When dealing with fmod(), Subclause F.10.7.1, paragraph 2, of the C Standard [ISO/IEC 9899:2011] states:
When subnormal results are supported, the returned value is exact and is independent of the current rounding direction mode.
Subclause F.10.7.2, paragraph 2, and Subclause F.10.7.3, paragraph 2 of the C Standard [ISO/IEC 9899:2011] covers remainder() and remquo() for when denormal results are supported.
Noncompliant Code Example (sqrt()
)
This noncompliant code example determines the square root of x
:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h>
void func(double x) {
double result;
result = sqrt(x);
} |
However, this code may produce a domain error if x
is negative.
Compliant Solution (sqrt()
)
Because this function has domain errors but no range errors, bounds checking can be used to prevent domain errors:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h>
void func(double x) {
double result;
if (isless(x, 0.0)) {
/* Handle domain error */
}
result = sqrt(x);
} |
Anchor | ||||
---|---|---|---|---|
|
Noncompliant Code Example (cosh()
, sinh()
, Range Errors)
This noncompliant code example determines the hyperbolic cosine of x
:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h>
void func(double x) {
double result;
result = sinh(x);
} |
This code may produce a range error if x
has a very large magnitude.
Compliant Solution (cosh()
, sinh()
, Range Errors)
Because this function has no domain errors but may have range errors, the programmer must detect a range error and act accordingly:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <errno.h>
#include <math.h>
#if defined(math_errhandling) \
&& (math_errhandling & MATH_ERREXCEPT)
#include <fenv.h>
#endif
void func(double x) {
double result;
errno = 0;
result = sinh(x);
#if defined(math_errhandling) \
&& (math_errhandling & MATH_ERREXCEPT)
feclearexcept(FE_ALL_EXCEPT);
#endif
#if !defined(math_errhandling) \
|| (math_errhandling & MATH_ERRNO)
if (errno != 0) {
/* Handle range error */
}
#endif
#if defined(math_errhandling) \
&& (math_errhandling & MATH_ERREXCEPT)
if (fetestexcept(FE_INVALID
| FE_DIVBYZERO
| FE_OVERFLOW
| FE_UNDERFLOW) != 0 | ||||
Code Block | ||||
| ||||
#include <math.h> void func(double x) { double result; if (isless(x, 0.0)) { /* Handle domainrange error */ } result = sqrt(x);#endif } |
Anchor | ||||
---|---|---|---|---|
|
Noncompliant Code Example (
...
pow()
...
)
...
This noncompliant code example determines the hyperbolic cosine of x
raises x
to the power of y
:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h> void func(double x, double y) { double result; result = sinhpow(x, y); } |
This However, this code may produce a domain error if x
is negative and y
is not an integer or if x
is 0 and y
is 0. A domain error or pole error may occur if x
is 0 and y
is negative, and a range error if x
has a very large magnitudemay occur if the result cannot be represented as a double
.
Compliant Solution (
...
pow()
...
)
Because this function has no domain errors but may have the pow()
function can produce domain errors, pole errors, and range errors, the programmer must detect first check that x
and y
lie within the proper domain and do not generate a pole error, then detect whether a range error occurs and act accordingly:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <errno.h> #include <math.h> #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) #include <errno.h> #include <math.h> <fenv.h> #endif void func(double x, double y) { #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) #include <fenv.h> #endif void func(double x) { feclearexcept(FE_ALL_EXCEPT); #endif errno = 0; double result; if (((x == 0.0f) errno = 0; result = sinh(x); #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) feclearexcept(FE_ALL_EXCEPT); #endif && islessequal(y, 0.0)) || isless(x, 0.0)) { /* Handle domain or pole error */ } result = pow(x, y); #if !defined(math_errhandling) \ || (math_errhandling & MATH_ERRNO) if (errno != 0) { /* Handle range error */ } #endif #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) if (fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW) != 0) { /* Handle range error */ } #endif } |
...
| FE_OVERFLOW
| FE_UNDERFLOW) != 0) {
/* Handle range error */
}
#endif
} |
Noncompliant Code Example (asin(),denormal argument)
This noncompliant code example determines the arcsin of x:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h>
void func(float x) {
float result;
result = asin(x);
} |
Compliant Soluction (asin(), denormal argument)
Because this function has no domain errors but may have range errors, the programmer must detect a range error
...
Noncompliant Code Example (pow()
)
This noncompliant code example raises x
to the power of y
:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h>
void func(double x, double y) {
double result;
result = pow(x, y);
} |
However, this code may produce a domain error if x
is negative and y
is not an integer or if x
is 0 and y
is 0. A domain error or pole error may occur if x
is 0 and y
is negative, and a range error may occur if the result cannot be represented as a double
.
Compliant Solution (pow()
)
Because the pow()
function can produce domain errors, pole errors, and range errors, the programmer must first check that x
and y
lie within the proper domain and do not generate a pole error, then detect whether a range error occurs and act accordingly:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <errno.h> #include <math.h> #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) #include <fenv<math.h> #endif void func(double x, double y) { #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) feclearexcept(FE_ALL_EXCEPT); #endif errno = 0; double result; if (((x == 0.0f) && islessequal(y, 0.0)) || isless(x, 0.0)) { /* Handle domain or pole error */ } result = pow(x, y); MATH_ERREXCEPT) #include <fenv.h> #endif void func(float x) { float result; errno = 0; result = asin(x); #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) feclearexcept(FE_ALL_EXCEPT); #endif #if !defined(math_errhandling) \ || (math_errhandling & MATH_ERRNO) if (errno != 0) { /* Handle range error */ } #endif #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) if (fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW) != 0) { /* Handle range error */ } #endif } |
Risk Assessment
Failure to prevent or detect domain and range errors in math functions may cause unexpected results.
...