Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: added section on range errors for functions with denormal arguments

...

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 

acos(x),

-1 <= x && x <= 1

No

No
asin (x)-1 <= x && x <= 1 YesNo
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

NoYes

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

NoYes

No

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

None

Yes

No

fdim(x,y)

None

Yes

No 

fma(x,y,z)

None

Yes

No

...

See FLP03-C. Detect and handle floating-point errors for more details on how to detect floating-point errors.

Anchor
Sqrt
Sqrt

Noncompliant Code Example (sqrt())

This noncompliant code example determines the square root of x:

Code Block
bgColor#FFcccc
langc
#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.

FunctionArguments
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
bgColor#FFcccc
langc
#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
bgColor#ccccff
langc
#include <math.h>
 
void func(double x) {
  double result;

  if (isless(x, 0.0)) {
    /* Handle domain error */
  }

  result = sqrt(x);
}

Anchor
HyperTrig
HyperTrig

Noncompliant Code Example (cosh(), sinh(), Range Errors)

This noncompliant code example determines the hyperbolic cosine of x:

Code Block
bgColor#FFcccc
langc
#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
bgColor#ccccff
langc
#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
bgColor#ccccff
langc
#include <math.h>
 
void func(double x) {
  double result;

  if (isless(x, 0.0)) {
    /* Handle domainrange error */
  }

  result = sqrt(x);#endif
}

Anchor
HyperTrigPowerHyperTrig
Power

Noncompliant Code Example (

...

pow()

...

)

...

This noncompliant code example determines the hyperbolic cosine of xraises x to the power of y:

Code Block
bgColor#FFcccc
langc
#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
bgColor#ccccff
langc
#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
bgColor#FFcccc
langc
#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
bgColor#FFcccc
langc
#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
bgColor#ccccff
langc
#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.

...