Linux下C庫學習
math.h
眾所周知,如果你想使用一些數學函式,那麼就需要包含math.h,這裡面基本包含了所有常用的數學函式(sin,cos,tan),以及數學常量(PI),等等,既然C庫裡面開發好了,那我們就看看到底裡面都有什麼。
既然是數學函式庫,首先我們就需要對運算元進行限制,比如0不能作為除數,對負數開方,對負數求對數等等,這些在數學上本身就是不合理的,那如果讓計算機去處理這些計算,很可能就會引起錯誤,因此我們首先就需要明確兩個概念inf(infinity)
和nan(not a number)
。
inf
infinity
字面意思是無窮大,這裡主要表示數值超過了浮點數的表示範圍溢位nan
not a number
當然這裡還有更嚴格的限制,比如
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裡面並沒有包含常見的數學函式,真正的數學函式都是定義在<bits/mathcalls.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
來包含數學庫。