Linux下C库学习 - math.h

math.h

众所周知,如果你想使用一些数学函数,那么就需要包含math.h,这里面基本包含了所有常用的数学函数(sin,cos,tan),以及数学常量(PI),等等,既然C库里面开发好了,那我们就看看到底里面都有什么。

既然是数学函数库,首先我们就需要对操作数进行限制,比如0不能作为除数,对负数开方,对负数求对数等等,这些在数学上本身就是不合理的,那如果让计算机去处理这些计算,很可能就会引起错误,因此我们首先就需要明确两个概念inf(infinity)nan(not a number)

  • inf
    infinity字面意思是无穷大,这里主要表示数值超过了浮点数的表示范围溢出

  • nan
    not a number字面意思是不是个数字,这就比较奇怪了,难道我用math.h不是为了操作数字吗?其实这里的意思主要是说你进行了未定义的操作,比如上面说的用0作为除数,对负数开方等等

当然这里还有更严格的限制,比如

1、nan == nan 结果是0或false,即不能和nan进行比较,和nan进行比较得到的结果总是false或0。
2、1.0 / 0.0等于inf,-1.0/0.0等于-inf即0.0 + inf = inf。
3、对负数开方sqrt(-1.0)、对负数求对数(log(-1.0))、0.0 / 0.0、0.0 * inf、inf / inf、inf - inf这些操作都会得到nan,但是不同的是0 / 0会产生操作异常而0.0 / 0.0不会产生操作异常,而是会得到nan
4、1.0/inf等于0.0。
5、inf是可以与其他浮点数进行比较的,即可以参与<=、>+、==、!=等运算。

既然有这么多限制,为了方便我们使用,math.h中提供了一系列宏和函数让你可以判断你进行的操作是否是inf,nan或者其他

具体的函数有如下几个

int fpclassify(x);
/* 用来查看浮点数x的情况,fpclassify可以用任何浮点数表达式作为参数。 */

int isfinite(x);
/* 当(fpclassify(x) != FP_NAN && fpclassify(x) != FP_INFINITE)时,此宏得到一个非零值。 */

int isnormal(x);
/* 当(fpclassify(x) == FP_NORMAL)时,此宏得到一个非零值。 */

int isnan(x);
/* 当(fpclassify(x)==FP_NAN)时,此宏返回一个非零值。 */

int isinf(x);
/* 当x是正无穷是返回1,当x是负无穷时返回-1。 */

这些函数的返回值可以用下面这几个宏来表示

FP_NAN: x是一个“not a number”。
FP_INFINITE: x是正、负无穷。
FP_ZERO: x是0。
FP_SUBNORMAL: x太小,以至于不能用浮点数的规格化形式表示。
FP_NORMAL: x是一个正常的浮点数(不是以上结果中的任何一种)

除了这些限制以外,math.h还做了一些数学常量的定义,比如

# define M_E        2.7182818284590452354   /* e */
# define M_LOG2E    1.4426950408889634074   /* log_2 e */
# define M_LOG10E   0.43429448190325182765  /* log_10 e */
# define M_LN2      0.69314718055994530942  /* log_e 2 */
# define M_LN10     2.30258509299404568402  /* log_e 10 */
# define M_PI       3.14159265358979323846  /* pi */
# define M_PI_2     1.57079632679489661923  /* pi/2 */
# define M_PI_4     0.78539816339744830962  /* pi/4 */
# define M_1_PI     0.31830988618379067154  /* 1/pi */
# define M_2_PI     0.63661977236758134308  /* 2/pi */
# define M_2_SQRTPI 1.12837916709551257390  /* 2/sqrt(pi) */
# define M_SQRT2    1.41421356237309504880  /* sqrt(2) */
# define M_SQRT1_2  0.70710678118654752440  /* 1/sqrt(2) */

看名字大家就应该明白是什么意思了,有了上面的提示,我们在使用数学函数的时候,如果报错就可以使用这些判断看看是否是我们的表达式不合理,并尽量使用库中定义好的常量避免发生错误,说完了这些限制,我们该看看真正的数学函数了,其实math.h里面并没有包含常见的数学函数,真正的数学函数都是定义在中,可能就是为了将这些限制性的规则以及定义和真正的函数区分开来,降低两者之间的耦合性,具体的函数有如下这些

  • 三角函数
double sin(double x); /* 正弦 */
double cos(double x); /* 余弦 */
double tan(double x); /* 正切 */
//*cot三角函数,可以使用tan(PI/2-x)来实现。
  • 反三角函数
double asin(double x); /* 结果介于[-PI/2, PI/2] */ 
double acos(double x); /* 结果介于[0, PI] */ 
double atan(double x); /* 反正切(主值), 结果介于[-PI/2, PI/2] */ 
double atan2(double y,double); /* 反正切(整圆值), 结果介于[-PI, PI] */
  • 双曲三角函数
double sinh(double x); /* 双曲正弦 */
double cosh(double x); /* 双曲余弦 */
double tanh(double x); /* 双曲正切 */
  • 反双曲三角函数
double acosh(double x); /* 反双曲余弦 */
float acoshf(float x);  /* 反双曲正弦 */
long double acoshl(long double x); /* 反双曲正切 */
  • 指数和对数
double exp(double x); /* 求取自然数e的幂 */
double exp2(double x); /* 求2的幂 */
double frexp(double x, int *exp);  /* 把一个浮点数分解为尾数和指数 */
double ldexp(double value, int exp);  /* 计算value乘以2的exp次幂(value * (2^exp)) */

double sqrt(double x); /* 开平方 */
double log(double x); /* 以e为底的对数 */

double log2(double x); /* 以2为底的对数 */
double log10(double x); /* 以10为底的对数 */

double log10(double x); / *以10为底的对数 */
double pow(double x, double y); /* 计算以x为底数的y次幂 */
float powf(float x, float y); /* 与pow一致,输入与输出皆为浮点数 */
  • 取整
double ceil(double); /* 取上整 */
double floor(double); /* 取下整 */
double fabs(double x); /* 取绝对值 */
double fmod(double x, double y); /* 对浮点数进行取模运算(%对整数进行取模运算) */
double round(double x); /* 四舍五入的数值 */
double trunc(double x); /* 去掉小数部分的整数 */

常用的函数大概就这么多了,实际我们在包含math.h并在用gcc编译的过程中,如果遇到undefined reference to 'xxxx'这样的错误提示,如果遇到这样的错误一定是缺少某个库,或者库的依赖关系和依赖顺序不正确,使用-l参数将库加入即可,Linux的库一般有三种libxxx.so,libxxx.a,libxxx.la,那么你要链接某个库就用-lxxx,去掉头lib及”.”后面的so,la,a等即可,因此,我们使用math.h的数学库的时候如果遇到这个错误,就应该使用-lm来包含数学库。

参考文献
http://blog.sina.com.cn/s/blog_8b745a5f01014ifk.html
http://ganquan.info/standard-c/

你可能感兴趣的:(Linux下C库学习)