Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

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.

...

...

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 

acos(x)

-1 <= x && x <= 1

No

No
asin(x)-1 <= x && x <= 1YesNo
atan(x)NoneYesNo

atan2(y, x)

x != 0 && y != 0

No

No

acosh(x)

x >= 1

Yes

No
asin(x)NoneYesNo

atanh(x)

-1 < x && x < 1

Yes

Yes

cosh(x), sinh(x)

None

Yes

No

exp(x), exp2(x), expm1(x)

None

Yes

No

ldexp(x, exp)

None

Yes

No

log(x), log10(x), log2(x)

x >= 0

No

Yes

log1p(x)

x > -1

No

Yes

ilogb(x)

x != 0 && !isinf(x) && !isnan(x)

Yes

No
logb(x)x != 0Yes Yes

scalbn(x, n), scalbln(x, n)

None

Yes

No

hypot(x, y)

None

Yes

No

pow(x,y)

x > 0 || (x == 0 && y > 0) ||
(x < 0 && y is an integer)

Yes

Yes

sqrt(x)

x >= 0

No

No
erf(x)NoneYesNo

erfc(x)

None

Yes

No

lgamma(x), tgamma(x)

x != 0 &&
! (x < 0 && x is an integer)

Yes

Yes

lrint(x), lround(x)

None

Yes

No

fmod(x, y), remainder(x, y),
remquo(x, y, quo)

y != 0

Yes

No

nextafter(x, y),
nexttoward(x, y)

None

Yes

No

fdim(x,y)

None

Yes

No 

fma(x,y,z)

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 and 0 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+subnorm), min)
  • remquo((min+subnorm), min, quo)

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
bgColor#FFcccc
langc
#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
bgColor#FFcccc
langc
#include <math.h>
 
void func(float x) {
  float result = asin(x);
  /* ... */
}

...

Bibliography

[ISO/IEC 9899:2011]

Subclause 7.3.2, "Conventions"
Subclause 7.12.1, "Treatment of Error Conditions"
Subclause F.10.7, "Remainder Functions" 

[IEEE 754 20062008 ] 
[Plum 1985]Rule 2-2
[Plum 1989]Topic 2.10, "conv—Conversions and Overflow"
[UNIX 1992]System V Interface Definition (SVID3)

...