Subclause The C Standard, 7.12.1 of the C Standard [ISO/IEC 9899:2011], defines three types of errors that relate specifically to math functions in math<math.hh>
. Paragraph 2 states:
... a A domain error occurs if an input argument is outside the domain over which the mathematical function is defined.
Paragraph 3 states:
... a A pole error (also known as a singularity or infinitary) occurs if the mathematical function has an exact infinite result as the finite input argument(s) are approached in the limit.
Paragraph 4 states:
...a A range error occurs if the mathematical result of the function cannot be represented in an object of the specified type, due to extreme magnitude.
An example of a domain error is the square root of a negative number, such as sqrt(-1.0)
, which has no meaning in real arithmetic.
...
Contrastingly, 10 raised to the 1-millionth power, pow(10., 1e6)
, cannot be represented in
...
many floating-point implementations because of the limited range of the type double
and consequently constitutes a range error. In both cases, the function will return some value, but the value returned is not the correct result of the computation. An example of a pole error is log(0.0)
, which results in negative infinity.
Domain Programmers can prevent domain and pole errors can be prevented by carefully bounds-checking the arguments before calling mathematical functions and taking alternative action if the bounds are violated.
...
The following table lists the double
forms of 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 Both float
and long double
forms of these function also exist but are omitted from the table for brevity. 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 fabs()
, 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 |
|
| Yes | 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 |
|
| Yes | No |
| None | Yes | No |
| None | Yes | No |
| None | Yes | No |
...
The most reliable way to handle domain and pole errors is to prevent them by checking arguments beforehand, as in the following templateexemplar:
Code Block |
---|
ifdouble safe_sqrt(/*double Argumentsx) that{ will causeif a(x domain or pole error */< 0) { /* Handle domain or pole error */ } else { /* Perform computation */fprintf(stderr, "sqrt requires a nonnegative argument"); return 0; } return sqrt (x); } |
Range Checking
Range errors Programmers usually cannot be preventedprevent range errors, so the most reliable way to handle range errors them is to detect when they have occurred and act accordingly.
The exact treatment of error conditions from math functions is quite complicated. Subclause tedious. The C Standard, 7.12.1 , paragraph 5, of the C Standard [ISO/IEC 9899:2011], defines the following behavior for floating-point overflow:
...
- These are, in general, valid (albeit unlikely) data values.
- Making such tests requires detailed knowledge of the various error returns for each math function.
- There are multiple different result possibilities Multiple results aside from
HUGE_VAL
and0
are possible, and you programmers must know which are possible in each case. - Different versions of the library have differed varied in their error-return behavior.
It is also difficult can be unreliable to check for math errors using errno
because an implementation might not set it errno
. For real functions, the programmer determines if the implementation sets errno
by checking whether math_errhandling & MATH_ERRNO
is nonzero. For complex functions, the C Standard, subclause 7.3.2, paragraph 1, simply states that "an implementation may set errno
but is not required to" [ISO/IEC 9899:2011].
The obsolete System V Interface Definition (SVID3) [UNIX 1992] provides more control over the treatment of errors in the math library. The user programmer can provide define a function named matherr()
that is invoked if errors occur in a math function. This function can print diagnostics, terminate the execution, or specify the desired return value. The matherr()
function has not been adopted by C or POSIX, so it is not generally portable.
...
Code Block |
---|
#include <math.h> #include <fenv.h> #include <errno.h> /* ... */ /* WhereUse you want to call a math function and check errors */ { #pragma STDC FENV_ACCESS ON if (math_errhandling & MATH_ERREXCEPT) { feclearexcept(FE_ALL_EXCEPT); } errno = 0; /* Call the math function */ if ((math_errhandling & MATH_ERRNO) && errno != 0) { /* Handle range error */ } else if ((math_errhandling & MATH_ERREXCEPT) && fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW) != 0) { /* Handle range error */ } } |
...
A subnormal number is a nonzero number that does not use all of its precision bits [IEEE 754 20062008 ]. They can be used to represent values that are closer to 0 than the smallest normal number (one that uses all of its precision bits). However, certain functions may produce range errors specifically when applied with a subnormal number. These functions are: the asin()
, asinh()
, atan()
, atanh()
, and erf()
. When evaluated functions may produce range errors specifically when passed a subnormal number. When evaluated with a subnormal number, these functions can produce an inexact, subnormal value, which is an underflow error. Subclause 7The C Standard, 7.12.1, paragraph 6 , of the C Standard [ISO/IEC 9899:2011], defines the following behavior for floating-point underflow:
...
Implementations that support floating-point arithmetic but which do not support subnormal numbers, such as IBM S/360 hex floating-point or nonconforming IEEE-754 implementations that skip subnormals (or support them by flushing them to zero), can return a range error when calling one of the following family families of functions with the following arguments:
fmod
((min+subnorm), min)
remainder
((min+
), min)subnorm
remquo
((min+
), min, quo)subnorm
Where where min
is the minimum value for the corresponding floating point type and subnorm
is a subnormal value.
If Annex F is fully supported and subnormal results are supported, the returned value is exact and there cannot be a range error cannot occur. The C Standard, F.10.7.1 [ISO/IEC 9899:2011], specifies the following for the fmod()
, remainder()
, and remquo()
functions:
When subnormal results are supported, the returned value is exact and is independent of the current rounding direction mode.
Subclause Annex F, subclause F.10.7.2, paragraph 2, and subclause F.10.7.3, paragraph 2 of 2, of the C Standard [ISO/IEC 9899:2011] cover for identify when subnormal results are supported.
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h> void func(double x, double y) { double result; result = pow(x, y); } |
However, this This code may produce a domain error if x
is negative and y
is not an integer value 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
.
...
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 , and then detect whether a range error occurs and act accordingly:
...
This noncompliant code example determines the inverse sine of x
:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h> void func(float x) { float result = asin(x); /* ... */ } |
...
Bibliography
[ISO/IEC 9899:2011] | Subclause 7.3.2, "Conventions" |
[IEEE 754 20062008 ] | |
[Plum 1985] | Rule 2-2 |
[Plum 1989] | Topic 2.10, "conv—Conversions and Overflow" |
[UNIX 1992] | System V Interface Definition (SVID3) |
...