C 编程/高等数学
<math.h>
头文件包含处理数学的几个函数的原型。在 1990 年的 ISO 标准中,只指定了函数的 double
版本;1999 年的版本添加了 float
和 long double
版本。要使用这些数学函数,您必须将程序与数学库链接。对于一些编译器(包括 GCC),您必须指定额外的参数 -lm
[1][2]。
数学函数可能会产生两种错误。域错误发生在函数参数无效时,例如,将负数作为参数传递给sqrt(平方根函数)。范围错误发生在函数结果无法用特定浮点类型表示时,例如pow(1000.0, 1000.0)如果 double 的最大值约为 10308。
这些函数可以分为以下几类
acos 函数返回其参数的反余弦值(以弧度为单位),asin 函数返回其参数的反正弦值(以弧度为单位)。所有函数都期望参数在 [-1,+1] 范围内。反余弦返回 [0,π] 范围内的值;反正弦返回 [-π/2,+π/2] 范围内的值。
#include <math.h>
float asinf(float x); /* C99 */
float acosf(float x); /* C99 */
double asin(double x);
double acos(double x);
long double asinl(long double x); /* C99 */
long double acosl(long double x); /* C99 */
atan 函数返回其参数的反正切值(以弧度为单位),atan2 函数返回 y/x
的反正切值(以弧度为单位)。atan 函数返回 [-π/2,+π/2] 范围内的值(±π/2 包含在范围内的原因是,浮点值可以表示无穷大,而 atan(±∞) = ±π/2);atan2 函数返回 [-π,+π] 范围内的值。对于 atan2,如果两个参数都为零,则可能会发生域错误。
#include <math.h>
float atanf(float x); /* C99 */
float atan2f(float y, float x); /* C99 */
double atan(double x);
double atan2(double y, double x);
long double atanl(long double x); /* C99 */
long double atan2l(long double y, long double x); /* C99 */
cos、sin 和 tan 函数分别返回参数的余弦、正弦和正切值,以弧度表示。
#include <math.h>
float cosf(float x); /* C99 */
float sinf(float x); /* C99 */
float tanf(float x); /* C99 */
double cos(double x);
double sin(double x);
double tan(double x);
long double cosl(long double x); /* C99 */
long double sinl(long double x); /* C99 */
long double tanl(long double x); /* C99 */
该cosh, sinh和tanh函数分别计算参数的双曲余弦、双曲正弦和双曲正切。对于双曲正弦和余弦函数,如果参数的大小太大,则会发生范围错误。
该acosh函数计算参数的反双曲余弦。对于小于 1 的参数,会发生域错误。
该asinh函数计算参数的反双曲正弦。
该atanh函数计算参数的反双曲正切。如果参数不在 [-1, +1] 区间内,则会发生域错误。如果参数等于 -1 或 +1,则可能发生范围错误。
#include <math.h>
float coshf(float x); /* C99 */
float sinhf(float x); /* C99 */
float tanhf(float x); /* C99 */
double cosh(double x);
double sinh(double x);
double tanh(double x);
long double coshl(long double x); /* C99 */
long double sinhl(long double x); /* C99 */
long double tanhl(long double x); /* C99 */
float acoshf(float x); /* C99 */
float asinhf(float x); /* C99 */
float atanhf(float x); /* C99 */
double acosh(double x); /* C99 */
double asinh(double x); /* C99 */
double atanh(double x); /* C99 */
long double acoshl(long double x); /* C99 */
long double asinhl(long double x); /* C99 */
long double atanhl(long double x); /* C99 */
exp 函数计算 x
的以 e 为底的指数函数 (ex)。如果 x
的大小太大,则会发生范围错误。
exp2 函数计算 x
的以 2 为底的指数函数 (2x)。如果 x
的大小太大,则会发生范围错误。
expm1 函数计算参数的以 e 为底的指数函数,减去 1。如果 x
的大小太大,则会发生范围错误。
#include <math.h>
float expf(float x); /* C99 */
double exp(double x);
long double expl(long double x); /* C99 */
float exp2f(float x); /* C99 */
double exp2(double x); /* C99 */
long double exp2l(long double x); /* C99 */
float expm1f(float x); /* C99 */
double expm1(double x); /* C99 */
long double expm1l(long double x); /* C99 */
这些函数在软件浮点模拟器中被大量使用,但在其他情况下很少被直接调用。
在计算机内部,每个浮点数都由两个部分表示
- 尾数要么在 [1/2, 1) 范围内,要么等于零。
- 指数是一个整数。
浮点数 的值是 .
frexp
函数将参数浮点数 value
分解为这两个部分:指数和尾数。分解后,它将指数存储在 ex
指向的 int
对象中,并返回尾数。换句话说,返回的值是给定浮点数的副本,但指数被替换为 0。如果 value
为零,则结果的两个部分均为零。
ldexp
函数将浮点数乘以 2 的整數次幂,并返回结果。换句话说,它返回给定浮点数的副本,其指数增加了 ex
。可能会发生范围错误。
modf
函数将参数 value
分解为整数部分和小数部分,它们都与参数具有相同的符号。它们将整数部分存储在 *iptr
指向的对象中,并返回小数部分。*iptr
是浮点类型,而不是 "int" 类型,因为它可能用于存储像 1 000 000 000 000 000 000 000 这样的整数,而这个整数太大,无法放入 int 中。
scalbn
和 scalbln
计算 x
× FLT_RADIXn
。FLT_RADIX
是浮点系统的基数;如果它是 2,则这些函数等效于 ldexp
。
#include <math.h>
float frexpf(float value, int *ex); /* C99 */
double frexp(double value, int *ex);
long double frexpl(long double value, int *ex); /* C99 */
float ldexpf(float x, int ex); /* C99 */
double ldexp(double x, int ex);
long double ldexpl(long double x, int ex); /* C99 */
float modff(float value, float *iptr); /* C99 */
double modf(double value, double *iptr);
long double modfl(long double value, long double *iptr); /* C99 */
float scalbnf(float x, int ex); /* C99 */
double scalbn(double x, int ex); /* C99 */
long double scalbnl(long double x, int ex); /* C99 */
float scalblnf(float x, long int ex); /* C99 */
double scalbln(double x, long int ex); /* C99 */
long double scalblnl(long double x, long int ex); /* C99 */
大多数 C 浮点库还实现了 IEEE754 推荐的 nextafter()、nextUp() 和 nextDown() 函数。 [3]
log
、log2
、log1p
和 log10
函数
[edit | edit source]log
函数计算参数的以 e 为底的自然对数,并返回结果。如果参数为负数,则会发生域错误。如果参数为零,则可能会发生范围错误。
log1p
函数计算参数加 1 的以 e 为底的自然对数,并返回结果。如果参数小于 -1,则会发生域错误。如果参数为 -1,则可能会发生范围错误。
log10
函数计算参数的以 10 为底的常用对数,并返回结果。如果参数为负数,则会发生域错误。如果参数为零,则可能会发生范围错误。
log2
函数计算参数的以 2 为底的对数,并返回结果。如果参数为负数,则会发生域错误。如果参数为零,则可能会发生范围错误。
#include <math.h>
float logf(float x); /* C99 */
double log(double x);
long double logl(long double x); /* C99 */
float log1pf(float x); /* C99 */
double log1p(double x); /* C99 */
long double log1pl(long double x); /* C99 */
float log10f(float x); /* C99 */
double log10(double x);
long double log10l(long double x); /* C99 */
float log2f(float x); /* C99 */
double log2(double x); /* C99 */
long double log2l(long double x); /* C99 */
ilogb
和 logb
函数
[edit | edit source]ilogb
函数将 x
的指数提取为带符号的 int 值。如果 x
为零,则它们返回 FP_ILOGB0
值;如果 x
为无穷大,则它们返回 INT_MAX
值;如果 x
为 NaN,则它们返回 FP_ILOGBNAN
值;否则,它们等效于调用相应的 logb
函数并将返回的值强制转换为 int
类型。如果 x
为零,则可能会发生范围错误。FP_ILOGB0
和 FP_ILOGBNAN
是在 math.h
中定义的宏;INT_MAX
是在 limits.h
中定义的宏。
logb
函数将 x
的指数提取为浮点格式的带符号整数。如果 x
为非规格化数,则将其视为规格化数;因此,对于正有限的 x
,1 ≤ x
× FLT_RADIX-logb(x)
< FLT_RADIX
。FLT_RADIX
是浮点数的基数,在 float.h
头文件中定义。
#include <math.h>
int ilogbf(float x); /* C99 */
int ilogb(double x); /* C99 */
int ilogbl(long double x); /* C99 */
float logbf(float x); /* C99 */
double logb(double x); /* C99 */
long double logbl(long double x); /* C99 */
幂函数
[edit | edit source]pow
函数
[edit | edit source]pow
函数计算 x
的 y
次幂,并返回结果。如果 x
为负数且 y
不是整数值,则会发生域错误。如果 x
为零且 y
小于或等于零,则结果无法表示,也会发生域错误。可能会发生范围错误。
#include <math.h>
float powf(float x, float y); /* C99 */
double pow(double x, double y);
long double powl(long double x, long double y); /* C99 */
sqrt
函数
[edit | edit source]sqrt
函数计算 x
的正平方根,并返回结果。如果参数为负数,则会发生域错误。
#include <math.h>
float sqrtf(float x); /* C99 */
double sqrt(double x);
long double sqrtl(long double x); /* C99 */
cbrt
函数
[edit | edit source]cbrt
函数计算 x
的立方根,并返回结果。
#include <math.h>
float cbrtf(float x); /* C99 */
double cbrt(double x); /* C99 */
long double cbrtl(long double x); /* C99 */
hypot
函数
[edit | edit source]hypot
函数计算 x
和 y
的平方和的平方根,避免溢出或下溢,并返回结果。
#include <math.h>
float hypotf(float x, float y); /* C99 */
double hypot(double x, double y); /* C99 */
long double hypotl(long double x, long double y); /* C99 */
最接近的整数、绝对值和余数函数
[edit | edit source]ceil
和 floor
函数
[edit | edit source]ceil
函数计算不小于 x
的最小整数值,并返回结果;floor
函数计算不大于 x
的最大整数值,并返回结果。
#include <math.h>
float ceilf(float x); /* C99 */
double ceil(double x);
long double ceill(long double x); /* C99 */
float floorf(float x); /* C99 */
double floor(double x);
long double floorl(long double x); /* C99 */
fabs
函数
[edit | edit source]fabs
函数计算浮点数 x
的绝对值,并返回结果。
#include <math.h>
float fabsf(float x); /* C99 */
double fabs(double x);
long double fabsl(long double x); /* C99 */
fmod
函数
[edit | edit source]fmod
函数计算 x/y
的浮点余数,并返回 x
- i * y
的值,其中 i 是某个整数,使得如果 y
不为零,则结果与 x
具有相同的符号,并且大小小于 y
的大小。如果 y
为零,则是否发生域错误或 fmod
函数返回零是实现定义的。
#include <math.h>
float fmodf(float x, float y); /* C99 */
double fmod(double x, double y);
long double fmodl(long double x, long double y); /* C99 */
nearbyint
函数将它们的实参四舍五入到浮点格式的整数值,使用当前的舍入方向,并且不会引发“不精确”浮点异常。
rint
函数类似于 nearbyint
函数,但如果结果与实参的值不同,它们可能会引发“不精确”浮点异常。
lrint
和 llrint
函数根据当前的舍入方向将它们的实参四舍五入到最接近的整数值。如果结果超出返回类型的值范围,则数值结果未定义,如果实参的大小过大,则可能会发生范围错误。
#include <math.h>
float nearbyintf(float x); /* C99 */
double nearbyint(double x); /* C99 */
long double nearbyintl(long double x); /* C99 */
float rintf(float x); /* C99 */
double rint(double x); /* C99 */
long double rintl(long double x); /* C99 */
long int lrintf(float x); /* C99 */
long int lrint(double x); /* C99 */
long int lrintl(long double x); /* C99 */
long long int llrintf(float x); /* C99 */
long long int llrint(double x); /* C99 */
long long int llrintl(long double x); /* C99 */
round
函数将实参四舍五入到浮点格式的最接近的整数值,无论当前的舍入方向如何,都将半途而废的情况四舍五入到远离零的方向。
lround
和 llround
函数将实参四舍五入到最接近的整数值,无论当前的舍入方向如何,都将半途而废的情况四舍五入到远离零的方向。如果结果超出返回类型的值范围,则数值结果未定义,如果实参的大小过大,则可能会发生范围错误。
#include <math.h>
float roundf(float x); /* C99 */
double round(double x); /* C99 */
long double roundl(long double x); /* C99 */
long int lroundf(float x); /* C99 */
long int lround(double x); /* C99 */
long int lroundl(long double x); /* C99 */
long long int llroundf(float x); /* C99 */
long long int llround(double x); /* C99 */
long long int llroundl(long double x); /* C99 */
trunc
函数将它们的实参四舍五入到浮点格式的整数值,该整数值最接近实参,但大小不超过实参。
#include <math.h>
float truncf(float x); /* C99 */
double trunc(double x); /* C99 */
long double truncl(long double x); /* C99 */
remainder
函数计算由 IEC 60559 定义的余数 x
REM y
。定义如下:“当 y ≠ 0 时,余数 r = x REM y 的定义与舍入模式无关,由数学归纳法 r = x - ny 定义,其中 n 是最接近 x/y 的精确值的整数;当 |n - x/y| = ½ 时,则 n 为偶数。因此,余数总是精确的。如果 r = 0,则它的符号应与 x 的符号相同。”此定义适用于所有实现。
#include <math.h>
float remainderf(float x, float y); /* C99 */
double remainder(double x, double y); /* C99 */
long double remainderl(long double x, long double y); /* C99 */
remquo
函数返回与 remainder
函数相同的余数。在由 quo
指向的对象中,它们存储一个值,该值的符号是 x
/y
的符号,并且该值的幅度对 2n 取模与 x
/y
的整数商的幅度一致,其中 n 是大于或等于 3 的实现定义的整数。
#include <math.h>
float remquof(float x, float y, int *quo); /* C99 */
double remquo(double x, double y, int *quo); /* C99 */
long double remquol(long double x, long double y, int *quo); /* C99 */
erf
函数计算实参 的误差函数。
erfc
函数计算实参的补误差函数(即 1 - erf x)。对于 erfc
函数,如果实参过大,则可能会发生范围错误。
lgamma
函数计算实参的伽马函数的绝对值的自然对数(即 loge|Γ(x)|)。如果实参为负整数或零,则可能会发生范围错误。
tgamma
函数计算实参的伽马函数(即 Γ(x))。如果实参为负整数,或者如果实参为零时结果无法表示,则会发生域错误。可能会发生范围错误。
#include <math.h>
float erff(float x); /* C99 */
double erf(double x); /* C99 */
long double erfl(long double x); /* C99 */
float erfcf(float x); /* C99 */
double erfc(double x); /* C99 */
long double erfcl(long double x); /* C99 */
float lgammaf(float x); /* C99 */
double lgamma(double x); /* C99 */
long double lgammal(long double x); /* C99 */
float tgammaf(float x); /* C99 */
double tgamma(double x); /* C99 */
long double tgammal(long double x); /* C99 */