16.2. Mathematical FunctionsThe standard library provides many mathematical functions. Most of them operate on real or complex floating-point numbers. However, there are also several functions with integer types, such as the functions to generate random numbers. The functions to convert numeral strings into arithmetic types are listed in "String Processing," later in this chapter. The remaining math functions are described in the following subsections. 16.2.1. Mathematical Functions for Integer TypesThe math functions for the integer types are declared in the header stdlib.h. Two of these functions, abs( ) and div( ), are declared in three variants to operate on the three signed integer types int, long, and long long. As Table 16-3 shows, the functions for the type long have names beginning with the letter l; those for long long with ll. Furthermore, the header inttypes.h declares function variants for the type intmax_t, with names that begin with imax.
16.2.2. Floating-Point FunctionsThe functions for real floating-point types are declared in the header math.h, and those for complex floating-point types in complex.h. Table 16-4 lists the functions that are available for both real and complex floating-point types. The complex versions of these functions have names that start with the prefix c. Table 16-5 lists the functions that are only defined for the real types; and Table 16-6 lists the functions that are specific to complex types. For the sake of readability, Tables 16-4 through 16-6 show only the names of the functions for the types double and double _Complex. Each of these functions also exists in variants for the types float (or float _Complex) and long double (or long double _Complex). The names of these variants end in the suffix f for float or l for long double. For example, the functions sin( ) and csin( ) listed in Table 16-4 also exist in the variants sinf( ), sinl( ), csinf( ), and csinl( ) (but see also "Type-generic macros" in the next section).
16.2.3. Function-like MacrosThe standard headers math.h and tgmath.h define a number of function-like macros that can be invoked with arguments of different floating-point types. Variable argument types in C are supported only in macros, not in function calls. 16.2.3.1. Type-generic macrosEach floating-point math function exists in three or six different versions: one for each of the three real types, or for each of the three complex types, or for both real and complex types. The header tgmath.h defines the type-generic macros , which allow you to call any version of a given function under a uniform name. The compiler detects the appropriate function from the arguments' type. Thus you do not need to edit the math function calls in your programs when you change an argument's type from double to long double, for example. The type-generic macros are described in the section on tgmath.h in Chapter 15. 16.2.3.2. Categories of floating-point valuesC99 defines five kinds of values for the real floating-point types, with distinct integer macros to designate them (see the section on math.h in Chapter 15): FP_ZERO FP_NORMAL FP_SUBNORMAL FP_INFINITE FP_NAN These classification macros, and the function-like macros listed in Table 16-7, are defined in the header math.h. The argument of each of the function-like macros must be an expression with a real floating-point type.
For example, the following two tests are equivalent: if ( fpclassify( x ) == FP_INFINITE ) /* ... */ ; if ( isinf( x ) ) /* ... */ ; 16.2.3.3. Comparison macrosAny two real, finite floating-point numbers can be compared. In other words, one is always less than, equal to, or greater than the other. However, if one or both operands of a comparative operator is a NaNa floating-point value that is not a numberfor example, then the operands are not comparable. In this case, the operation yields the value 0, or "false," and may raise the floating-point exception FE_INVALID. In practice, you may want to avoid risking an exception when comparing floating-point objects. For this reason, the header math.h defines the function-like macros listed in Table 16-8. These macros yield the same results as the corresponding expressions with comparative operators, but perform a "quiet" comparison; that is, they never raise exceptions. The two arguments of each macro must be expressions with real floating-point types.
16.2.4. Pragmas for Arithmetic OperationsThe following two standard pragmas influence the way in which arithmetic expressions are compiled: #pragma STDC FP_CONTRACT on_off_switch #pragma STDC CX_LIMITED_RANGE on_off_switch The value of on_off_switch must be ON, OFF, or DEFAULT. If switched ON, the first of these pragmas, FP_CONTRACT, allows the compiler to contract floating-point expressions with several C operators into fewer machine operations, if possible. Contracted expressions are faster in execution. However, because they also eliminate rounding errors, they may not yield precisely the same results as uncontracted expressions. Furthermore, an uncontracted expression may raise floating-point exceptions that are not raised by the corresponding contracted expression. It is up to the compiler to determine how contractions are performed, and whether expressions are contracted by default. The second pragma, CX_LIMITED_RANGE , affects the multiplication, division, and absolute values of complex numbers. These operations can cause problems if their operands are infinite, or if they result in invalid overflows or underflows. When switched ON, the pragma CX_LIMITED_RANGE instructs the compiler that it is safe to use simple arithmetic methods for these three operations, as only finite operands will be used, and no overflows or underflows need to be handled. By default, this pragma is switched OFF. In source code, these pragma directives can be placed outside all functions, or at the beginning of a block, before any declarations or statements. The pragmas take effect from the point where they occur in the source code. If a pragma directive is placed outside all functions, its effect ends with the next directive that invokes the same pragma, or at the end of the translation unit. If the pragma directive is placed within a block, its effect ends with the next directive that invokes the same pragma in a nested block, or at the end of the containing block. At the end of a block, the compiler behavior returns to the state that was in effect at the beginning of the block. 16.2.5. The Floating-Point EnvironmentThe floating-point environment consists of system variables for floating-point status flags and control modes. Status flags are set by operations that raise floating-point exceptions, such as division by zero. Control modes are features of floating-point arithmetic behavior that programs can set, such as the way in which results are rounded to representable values. Support for floating-point exceptions and control modes is optional. All of the declarations involved in accessing the floating-point environment are contained in the header fenv.h (see Chapter 15). Programs that access the floating-point environment should inform the compiler beforehand by means of the following standard pragma: #pragma STDC FENV_ACCESS ON This directive prevents the compiler from applying optimizations, such as changes in the order in which expressions are evaluated, that might interfere with querying status flags or applying control modes. FENV_ACCESS can be applied in the same ways as FP_CONTRACT and CX_LIMITED_RANGE: outside all functions, or locally within a block (see the preceding section). It is up to the compiler whether the default state of FENV_ACCESS is ON or OFF. 16.2.5.1. Accessing status flagsThe functions in Table 16-9 allow you to access the exception status flags. One argument to these functions indicates the kind or kinds of exceptions to operate on. The following integer macros are defined in the header fenv.h to designate the individual exception types: FE_DIVBYZERO FE_INEXACT FE_INVALID FE_OVERFLOW FE_UNDERFLOW Each of these macros is defined only if the implementation supports the corresponding exception. The macro FE_ALL_EXCEPT designates all the supported exception types.
16.2.5.2. Rounding modesThe floating-point environment also includes the rounding mode currently in effect for floating-point operations. The header fenv.h defines a distinct integer macro for each supported rounding mode. Each of the following macros is defined only if the implementation supports the corresponding rounding direction: FE_DOWNWARD FE_TONEAREST FE_TOWARDZERO FE_UPWARD Implementations may also define other rounding modes and macro names for them. The values of these macros are used as return values or as argument values by the functions listed in Table 16-10.
16.2.5.3. Saving the whole floating-point environmentThe functions listed in Table 16-11 operate on the floating-point environment as a whole, allowing you to save and restore the floating-point environment's state.
16.2.6. Error HandlingC99 defines the behavior of the functions declared in math.h in cases of invalid arguments or mathematical results that are out of range. The value of the macro math_errhandling, which is constant throughout a program's runtime, indicates whether the program can handle errors using the global error variable errno, or the exception flags in the floating-point environment, or both. 16.2.6.1. Domain errorsA domain error occurs when a function is mathematically not defined for a given argument value. For example, the real square root function sqrt( ) is not defined for negative argument values. The domain of each function in math.h is indicated in the description in Chapter 17. In the case of a domain error, functions return a value determined by the implementation. In addition, if the expression math_errhandling & MATH_ERRNO is not equal to zeroin other words if the expression is truethen a function incurring a domain error sets the error variable errno to the value of EDOM. If the expression math_errhandling & MATH_ERREXCEPT is true, then the function raises the floating-point exception FE_INVALID. 16.2.6.2. Range errorsA range error occurs if the mathematical result of a function is not representable in the function's return type without a substantial rounding error. An overflow occurs if the range error is due to a mathematical result whose magnitude is finite, but too large to be represented by the function's return type. If the default rounding mode is in effect when an overflow occurs, or if the exact result is infinity, then the function returns the value of HUGE_VAL (or HUGE_VALF or HUGE_VALL, if the function's type is float or long double) with the appropriate sign. In addition, if the expression math_errhandling & MATH_ERRNO is true, then the function sets the error variable errno to the value of ERANGE. If the expression math_errhandling & MATH_ERREXCEPT is true, then an overflow raises the exception FE_OVERFLOW if the mathematical result is finite, or FE_DIVBYZERO if it is infinite. An underflow occurs when a range error is due to a mathematical result whose magnitude is nonzero, but too small to be represented by the function's return type. When an underflow occurs, the function returns a value which is defined by the implementation, but less than or equal to the value of DBL_MIN (or FLT_MIN, or LDBL_MIN, depending on the function's type). The implementation also determines whether the function sets the error variable errno to the value of ERANGE if the expression math_errhandling & MATH_ERRNO is true. Furthermore, the implementation defines whether an underflow raises the exception FE_UNDERFLOW if the expression math_errhandling & MATH_ERREXCEPT is true. |