日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

c语言定义小数无穷小,OC中常用的数学函数以及浮点处理函数

發(fā)布時間:2024/4/19 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言定义小数无穷小,OC中常用的数学函数以及浮点处理函数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在編程中我們總要進行一些數(shù)學運算以及數(shù)字處理,尤其是浮點數(shù)的運算和處理,這篇文章主要介紹C語言下的數(shù)學庫。而其他語言中的數(shù)學庫函數(shù)的定義以及最終實現(xiàn)也是通過對C數(shù)學庫的調(diào)用來完成的,其內(nèi)容大同小異,因此就不在這里介紹了。

C語言標準庫中的math.h定義了非常多的數(shù)學運算和數(shù)字處理函數(shù)。這些函數(shù)大部分都是在C89標準中定義的,而有些C99標準下的函數(shù)我會特殊的說明,同時因為不同的編譯器下的C標準庫中有些函數(shù)的定義有差別,我也會分別的說明。

數(shù)字的范圍

整型

整型用來存儲整數(shù)數(shù)值,它按存儲的字節(jié)長短分為:字符型,短整型,整型,長整型。 所有類型的存儲長度都是定長的。既然類型是定長的就有一個最大最小可表示的范圍,對于整型來說各種類型的最大最小的定義可以在limits.h中找到。下面表格列出了不同類型的存儲長度和最大最小值:

類型字節(jié)數(shù)最小值宏定義最大值宏定義備注char1-2^7SCHAR_MIN2^7-1SCHAR_MAX

unsigned char10UCHAR_MIN2^8-1UCHAR_MAX

short2-2^15SHRT_MIN2^15-1SHRT_MAX

unsigned short20USHRT_MIN2^16-1USHRT_MAX

int4?-2^31INT_MIN2^31-1INT_MAX

unsinged int4?0UINT_MIN2^32-1UINT_MAX

long4?-2^31LONG_MIN2^31-1LONG_MAX

unsigned long4?0ULONG_MIN2^32-1ULONG_MAX

long long8-2^63LLONG_MIN2^63-1LLONG_MAXC99

unsigned long long80ULLONG_MIN2^64-1ULLONG_MAXC99

對于int和long類型來說,二者的長度是依賴于操作系統(tǒng)的字長或者機器的字長。因此如果我們要編寫跨平臺或跨系統(tǒng)的程序就應(yīng)該盡量減少對這兩個類型變量的直接定義。 下面表格列出了int和long兩種類型在不同操作系統(tǒng)字長下的長度。

類型16位系統(tǒng)/字節(jié)32位系統(tǒng)/字節(jié)64位系統(tǒng)/字節(jié)int244

long448

在很多系統(tǒng)中都對32位的整型以及64位的整型進行特殊的定義,比如Windows中的DWORD,UINT32,INT64等等。

浮點型

浮點型用來存儲浮點數(shù)值。它按精度分為:單精度浮點型,雙精度浮點型,擴展雙精度浮點型。 浮點數(shù)是連續(xù)并且無限的,但是計算機并不能表達出所有連續(xù)的值。因此對浮點數(shù)定義了最小規(guī)格化值和最大規(guī)格化值,這些定義可以在float.h中找到。下面表格列出了不同類型的存儲長度和最值:

類型字節(jié)數(shù)最小規(guī)格化值宏定義最大規(guī)格化值宏定義備注float41.175494351e-38FLT_MIN3.402823466e+38FLT_MAX

double82.2250738585072014e-308DBL_MIN1.7976931348623158e+308DBL_MAX

long double8?2.2250738585072014e-308LDBL_MIN1.7976931348623158e+308LDBL_MAXC99

這里的FLT_MIN,DBL_MIN,LDBL_MIN并不是指最小可表示的浮點數(shù),而是最小規(guī)格化浮點值,具體我會在下面詳細介紹。

對 long double 的定義,取決于編譯器和機器字長,所以對于不同平臺可能有不同的實現(xiàn),有的是8字節(jié),有的是10字節(jié),有的是12字節(jié)或16字節(jié)。

為了和數(shù)學中的無窮∞對應(yīng),標準庫中定義了一個宏:INFINITY來表示無窮大。比如1.0/0.0等于INFINITY,-1.0/0.0等于-INFINITY。無窮大可以進行加減乘除操作,比如1.0/INFINITY == 0。

為了和數(shù)學中的非法數(shù)字對應(yīng),標準庫中定義了一個宏:NAN來表示非法數(shù)字。比如負數(shù)開方、負數(shù)求對數(shù)、0.0/0.0、0.0* INFINITY、INFINITY/INFINITY、INFINITY-INFINITY這些操作都會得到NAN。注意:如果是整數(shù)0/0會產(chǎn)生操作異常

浮點數(shù)的存儲結(jié)構(gòu)

浮點數(shù)不像整數(shù)那樣離散值,而是連續(xù)的值。但是用計算機來描述一個浮點數(shù)時就不可能完全實現(xiàn)其精度和連續(xù)性,現(xiàn)在的浮點型的存儲和描述普遍都是遵循IEEE754標準。如果您想詳細的了解關(guān)于浮點數(shù)的存儲格式那么您可以花費一點時間來閱讀:https://wenku.baidu.com/view/d02978d8d15abe23482f4dac.html?這篇文章。

簡單來說浮點數(shù)的存儲由:S(sign)符號位、E(exponent)指數(shù)位、M(mantissa 或significand)尾數(shù)位三個部分組成。我們以一個32位的float類型舉例來說,一個浮點數(shù)N的從高位到低位的存儲結(jié)構(gòu)如下:

也就是一個32位的浮點數(shù)由1個符號位,8個指數(shù)位,23個尾數(shù)位組成。 而為了表示不同類型的浮點數(shù),根據(jù)存儲格式對浮點數(shù)進行了如下分類:如果一個浮點數(shù)中指數(shù)位部分全為1,而尾數(shù)位部分全為0則這個浮點數(shù)表示為無窮大INFINITY,如果符號位為0表示正無窮大,否則就是負無窮大。

如果一個浮點數(shù)中指數(shù)位部分全為1,而尾數(shù)位部分不全為0則這個浮點數(shù)表示為非法數(shù)字NAN。因此可以看出非法數(shù)字并非一個數(shù)字而是一類數(shù)字。在下面介紹nan函數(shù)時我會更加深入的介紹NAN

如果一個浮點數(shù)中除符號位外全部都是0,那么這個浮點數(shù)就是0

如果一個浮點數(shù)中指數(shù)位部分全為0,而尾數(shù)位部分不全為0則這個浮點數(shù)稱為非規(guī)格化浮點數(shù),英文稱為:subnormal number 或 denormal number 或 denormalized number。非規(guī)格化浮點數(shù)常用來表示一個非常接近于0的浮點數(shù)。

如果一個浮點數(shù)中的指數(shù)位部分即非全1又非全0。那么這個浮點數(shù)稱之為規(guī)格化浮點數(shù),英文稱之為:normal number。我們上面定義的FLT_MIN, DBL_MIN?指的就是最小的規(guī)格化浮點數(shù)。

我們把規(guī)格化浮點數(shù)和非規(guī)格化浮點數(shù)合稱為可表示的浮點數(shù),英文稱之為:machine representable number

一個規(guī)格化浮點數(shù)N的值可以用如下公式算出:

從上面的公式中可以看出對于一個32位浮點數(shù)來說,指數(shù)位占8位,最小值是1(全0為非常規(guī)浮點),而最大值是254(全1為無窮或者非法浮點),而減去127則表示指數(shù)部分的最小值為-126,最大值為127;同時我們發(fā)現(xiàn)除了23位尾數(shù)外,還有一個隱藏的1作為尾數(shù)的頭部。因此我們就很容易得出:FLT_MIN = 1.0 * 2^-126 = 1.175494351e-38FLT_MAX = (1.11111111111111111111111)b * 2^127 = 3.402823466e+38

一個非規(guī)格化浮點數(shù)N的值的可以用如下公式算出:

從上面的公式中可以看出對于一個32位的浮點數(shù)來說,我們發(fā)現(xiàn)雖然非規(guī)格化浮點的指數(shù)位部分全0,但是這里并不是0-127,而是1-127,同時發(fā)現(xiàn)尾數(shù)位部分并沒有使用隱藏的1作為尾數(shù)的頭部,而是將頭部的1移到了指數(shù)部分,這樣做的目的是為了保持浮點數(shù)字的連續(xù)性。我們可以看出當一個浮點數(shù)小于FLT_MIN時,他就變?yōu)榱艘粋€非規(guī)格化浮點。我們知道FLT_MIN的值是1.0 * 2^-126,而一個比FLT_MIN小的值就應(yīng)該是:(0.11111111111111111111111)b * 2^-126,而一個比0大的值就是:(0.00000000000000000000001)b * 2^-126。如果非規(guī)格化浮點數(shù)以-127作為指數(shù),而繼續(xù)使用1作為尾數(shù)的頭部時,那么這種數(shù)字連續(xù)性將會被打破。這也是為什么要定義規(guī)格化浮點數(shù)和非規(guī)格化浮點數(shù)的意義所在。可以看出浮點數(shù)的這種存儲設(shè)計的精妙之處!!。

從上面兩種類型的浮點數(shù)中可以總結(jié)出浮點數(shù)的計算公式可以表示為:N = 符號 * 尾數(shù) * 2^指數(shù)

數(shù)學函數(shù)

數(shù)字判斷函數(shù)或宏//如果x是正無窮大返回1,負無窮大返回-1,否則返回0int?isinf(x)

//如果x是無窮大返回0int?isfinite(x)

//如果x是一個規(guī)格化浮點數(shù)則返回非0int??isnormal(x)

//如果x是一個非法的數(shù)字返回非0int?isnan(x)

//如果x是負數(shù)返回非0int?signbit(x)

/**

*返回浮點數(shù)的分類:

FP_INFINITE:??x是無窮大或者無窮小

FP_NAN:x是一個非法數(shù)字

FP_NORMAL:x是一個規(guī)格化浮點數(shù)

FP_SUBNORMAL:x是一個非規(guī)格化浮點數(shù)

FP_ZERO:x是0*/

int??fpclassify(x)

三角函數(shù)

1. 反余弦函數(shù):?y = arccos(x)extern?float?acosf(float?x);

extern?double?acos(double?x);

extern?long?double?acosl(long?double?x);

2. 反正弦函數(shù):y = arcsin(x)extern?float?asinf(float?x);

extern?double?asin(double?x);

extern?long?double?asinl(long?double?x);

3. 反正切函數(shù):y = arctan(x)extern?float?atanf(float?x);

extern?double?atan(double?x);

extern?long?double?atanl(long?double?x);

4. 2個參數(shù)的反正切函數(shù):z = arctan(y/x)extern?float?atan2f(float?y,?float?x);

extern?double?atan2(double?y,?double?x);

extern?long?double?atan2l(long?double?y,?long?double?x);

因為arctan的定義域是在(-∞, +∞),而值域是在(-????/2, ????/2)之間。因此 :atan2f(-1.0, 0.0) == -????/2; ?atan2f(1.0, 0.0) == ????/2;這個函數(shù)提供的另外一個意義在于tan函數(shù)的值其實就是對邊除以鄰邊的結(jié)果,因此當知道對邊和鄰邊時就可以直接用這個逆三角函數(shù)來求得對應(yīng)的弧度值。假如特殊情況下對邊和鄰邊的值都是0.0,那么如果你調(diào)用atan(0.0/0.0)得到的值將是NAN而不是0。因為0.0/0.0的值是NAN,而對NAN調(diào)用atan函數(shù)返回的也是NAN,但是對atan2(0.0,0.0)調(diào)用返回的結(jié)果就是正確值0。

5. 余弦函數(shù):?y = cos(x)extern?float?cosf(float?x);

extern?double?cos(double?x);

extern?long?double?cosl(long?double?x);

6. 正弦函數(shù):y = sin(x)extern?float?sinf(float?x);

extern?double?sin(double?x);

extern?long?double?sinl(long?double?x);

7. 正切函數(shù):y = tan(x)extern?float?tanf(float?x);

extern?double?tan(double?x);

extern?long?double?tanl(long?double?x);

雙曲函數(shù)

1. 反雙曲余弦函數(shù):y = arccosh(x)extern?float?acoshf(float?x);

extern?double?acosh(double?x);

extern?long?double?acoshl(long?double?x);

2. 反雙曲正弦函數(shù):y = arcsinh(x)extern?float?asinhf(float?x);

extern?double?asinh(double?x);

extern?long?double?asinhl(long?double?x);

3. 反雙曲正切函數(shù):y = arctanh(x)extern?float?atanhf(float?x);

extern?double?atanh(double?x);

extern?long?double?atanhl(long?double?x);

4. 雙曲余弦函數(shù):y = cosh(x)extern?float?coshf(float?x);

extern?double?cosh(double?x);

extern?long?double?coshl(long?double?x);

5. 雙曲正弦函數(shù):y = sinh(x)extern?float?sinhf(float?x);

extern?double?sinh(double?x);

extern?long?double?sinhl(long?double?x);

6. 雙曲正切函數(shù):?y = tanh(x)extern?float?tanhf(float?x);

extern?double?tanh(double?x);

extern?long?double?tanhl(long?double?x);

指數(shù)函數(shù)

1. 自然常數(shù)e為基數(shù)的指數(shù)函數(shù):y = e^xextern?float?expf(float?x);

extern?double?exp(double?x);

extern?long?double?expl(long?double?x);

2. 自然常數(shù)e為基數(shù)的指數(shù)減1:y = e^x - 1extern?float?expm1f(float?x);

extern?double?expm1(double?x);

extern?long?double?expm1l(long?double?x);

我們既然定義了exp函數(shù),那么按理說要實現(xiàn)e^x-1就很簡單,為什么要單獨定義這個函數(shù)呢?先看下面兩個輸出:double?o1?=?exp(1.0e-13)?-?1.0;

double?o2?=?expm1(1.0e-13);

printf("o1?=?%e,?o2?=?%e",?o1,?o2);

//output:???o1?=?9.992007e-14,?o2?=?1.000000e-13

從上面的例子中發(fā)現(xiàn)當用exp函數(shù)時出現(xiàn)了有效數(shù)字損失而expm1則沒有。出現(xiàn)這種問題的原因就是浮點加減運算本身機制的問題,在浮點運算中下面兩種類型的運算都有可能出現(xiàn)損失有效數(shù)字的情況:兩個相近的數(shù)相減

兩個數(shù)量級相差很大的數(shù)字相加減

我們可以做一個實驗,分別在調(diào)試器中查看a1,a2和b1,b2的結(jié)果:double?a1?=?5.37-5.36;

double?a2?=?(5.37*100?-?5.36*100)/100;

double?b1?=?100.0-0.01;

double?b2?=?(100.0/0.01?-?0.01/0.01)*0.01;//我們發(fā)現(xiàn)a1的值是0.0099999999999997868,而a2的值就是0.01//我們發(fā)現(xiàn)b1的值是99.989999999999994而b2的值是99.990000000000009

從上面的例子中可以看出當浮點數(shù)相近或者差異很大時加減運算出現(xiàn)了有效數(shù)字損失的情況,同時上面的例子也給出了一個減少這種損失的簡易解決方案。再回到上面exp函數(shù)的場景中,因為exp(1.0e-13)的值和1.0是非常接近,因此當對這兩個數(shù)做減法時就會出現(xiàn)有效數(shù)字損失的情況。我們再來考察expm1函數(shù),這個函數(shù)主要用于當x接近于0時的場景。我們知道函數(shù)?y = e^x - 1?當x趨近于0時的極限是0,因此我們可以用泰勒級數(shù)來展開他:

可以看出這個級數(shù)收斂的很快,因此可以肯定的是expm1函數(shù)的內(nèi)部實現(xiàn)就是通過上面的泰勒級數(shù)的方法來實現(xiàn)求值的。下面這段函數(shù)使用手冊的文檔也給出了用expm1代替exp函數(shù)的例子和說明:Note?that?computations?numerically?equivalent?to?exp(x)?-?1.0?are?often

hidden?in?more?complicated?expressions;?some?amount?of?algebraic?manipu-

lation?may?be?necessary?to?take?advantage?of?the?expm1()?function.??Con-

sider?the?following?example,?abstracted?from?a?developer's?actual?produc-

tion?code?in?a?bug?report:???????????double?z?=?exp(-x/y)*(x*x/y/y?+?2*x/y?+?2)?-?2

When?x?is?small?relative?to?y,?this?expression?is?approximately?equal?to:???????????double?z?=?2*(exp(-x/y)?-?1)?????and?all?precision?of?the?result?is?lost?in?the?computation?due?to?cata-

strophic?cancellation.??The?developer?was?aware?that?they?were?losing

precision,?but?didn't?know?what?to?do?about?it.??To?remedy?the?situation,

we?do?a?little?algebra?and?re-write?the?expression?to?take?advantage?of

the?expm1()?function:

exp(-x/y)*(x*x/y/y?+?2*x/y?+?2)?-?2

=?(2*exp(-x/y)?-?2)?+?exp(-x/y)*((x*x)/(y*y)?+?2*x/y)

This?transformation?allows?the?result?to?be?computed?to?a?high?degree?of

accuracy?as?follows:???????????const?double?r?=?x/y;???????????const?double?emrm1?=?expm1(-r);???????????double?z?=?2.0*emrm1?+?(1.0?+?emrm1)*(2.0?+?r)*r;

It?is?not?always?easy?to?spot?such?opportunities?for?improvement;?if?an

expression?involving?exp()?seems?to?be?suffering?from?an?undue?loss?of

accuracy,?try?a?few?simple?algebraic?operations?to?see?if?you?can?iden-

tify?a?factor?with?the?form?exp(x)?-?1.0,?and?substitute?expm1(x)?in?its

place.

3. 2為基數(shù)的指數(shù)函數(shù):y = 2^xextern?float?exp2f(float?x);

extern?double?exp2(double?x);

extern?long?double?exp2l(long?double?x);

4. 浮點數(shù)構(gòu)造函數(shù):y = x * 2^nextern?float?ldexpf(float?x,?int?n);

extern?double?ldexp(double?x,?int?n);

extern?long?double?ldexpl(long?double?x,?int?n);

既然上面已經(jīng)存在了一個exp函數(shù),如果我們要實現(xiàn)相同的功能按理來只要:x*exp(n)就好了,為什么還要單獨提供一個新的ldexp函數(shù)呢?原因就是ldexp函數(shù)其實是一個用來構(gòu)造浮點數(shù)的函數(shù),我們知道浮點數(shù)的格式定義在符號*尾數(shù)*2^指數(shù),剛好和ldexp所實現(xiàn)的功能是一致的,這里的x用來指定符號*尾數(shù),而n則指定為指數(shù)。因此我們就可以借助這個函數(shù)來實現(xiàn)浮點數(shù)的構(gòu)造。

5. 以FLT_RADIX基數(shù)的浮點數(shù)構(gòu)造函數(shù):y = x* FLT_RADIX^nextern?float?scalbnf(float?x,?int?n);

extern?double?scalbn(double?x,?int?n);

extern?long?double?scalbnl(long?double?x,?int?n);

extern?float?scalblnf(float?x,?long?int?n);

extern?double?scalbln(double?x,?long?int?n);

extern?long?double?scalblnl(long?double?x,?long?int?n);

這里的FLT_RADIX是浮點數(shù)存儲里面的基數(shù)(在float.h中有定義這個宏),一般情況下是2,這時候這個函數(shù)就和ldexp函數(shù)是一致的。但是有些系統(tǒng)的浮點數(shù)存儲并不是以2為基數(shù)(比如IBM 360的機器)。因此如果你要構(gòu)造一個和機器相關(guān)的浮點數(shù)時就用這個函數(shù)。

對數(shù)函數(shù)

1. 自然常數(shù)e為基數(shù)的對數(shù)函數(shù):y = ln(x)extern?float?logf(float?x);

extern?double?log(double?x);

extern?long?double?logl(long?double?x);

2. 自然常數(shù)e為基數(shù)的對數(shù)函數(shù):?y = ln(x + 1)extern?float?log1pf(float?x);

extern?double?log1p(double?x);

extern?long?double?log1pl(long?double?x);

這個函數(shù)的使用場景主要用于當x趨近于0的情況,上面曾經(jīng)描述過當兩個浮點數(shù)之間的數(shù)量值相差很大時數(shù)字的加減會存在有效位丟失的情況。因此如果我們用log函數(shù)來計算時當x趨近于0的ln(x+1)時就會存在有效位的損失情況。比如下面的例子:double?o1?=?log(1.0e-13?+?1);

double?o2?=?log1p(1.0e-13);

printf("o1?=?%e,?o2?=?%e",?o1,?o2);

//output:?o1?=?9.992007e-14,?o2?=?1.000000e-13

可以看出函數(shù)log1p主要用于當x接近于0時的場景。我們知道函數(shù) y = ln(x+1) 當x趨近于0時的極限是0,因此我們可以用泰勒級數(shù)來展開他:

可以看出這個級數(shù)收斂的很快,因此可以肯定的是log1p函數(shù)的內(nèi)部實現(xiàn)就是通過上面的泰勒級數(shù)的方法來實現(xiàn)求值的。

3. 10為基數(shù)的對數(shù)函數(shù):y = log10(x)extern?float?log10f(float?x);

extern?double?log10(double?x);

extern?long?double?log10l(long?double?x);

4. 2為基數(shù)的對數(shù)函數(shù)1:y = log2(x)extern?float?log2f(float?x);

extern?double?log2(double?x);

extern?long?double?log2l(long?double?x);

5. FLT_RADIX為基數(shù)的對數(shù)函數(shù)并取整:y = floor(log2(x))extern?float?logbf(float?x);

extern?double?logb(double?x);

extern?long?double?logbl(long?double?x);

函數(shù)返回的是一個小于等于真實指數(shù)的最大整數(shù),也就是對返回的值進行了floor操作,具體floor函數(shù)的定義見下面。這里的FLT_RADIX是浮點數(shù)的基數(shù),大部分系統(tǒng)定義為2。下面是這個函數(shù)的一些例子:logb(2.5)?==?floor(log2(2.5))?==?1;

logb(4.0)?==?floor(log2(4.0))?==?2;

logb(4.1)?==?floor(log2(4.1))?==?2;

logb(7)?==?floor(log2(7))?==?2;

logb(7.9999)?==?floor(log2(7.9999))?==?2;

logb(8.0)?==?floor(log2(8.0))?==?3;

6. FLT_RADIX為基數(shù)的對數(shù)函數(shù)并取整:y = floor(log2(x))extern?int?ilogbf(float?x);

extern?int?ilogb(double?x);

extern?int?ilogbl(long?double?x);

函數(shù)返回的是一個小于等于真實指數(shù)的最大整數(shù),也就是對返回的值進行了floor操作,具體floor函數(shù)的定義見下面。需要注意的是這里返回的類型是整型,因此不可能存在返回NAN或者INFINITY的情況。下面是當x是0或者負數(shù)時返回的特殊值:FP_ILOGB0:??當x是0時返回這個特殊值。

FP_ILOGBNAN:當x是負數(shù)時返回這個特殊值。

這里區(qū)分一下log2,logb,ilogb?這三個函數(shù)的差異:logb,ilogb是以FLT_RADIX為基數(shù)的對數(shù),而log2則是以2為基數(shù)的對數(shù),雖然大部分系統(tǒng)中FLT_RADIX默認是定義為2。

log2,logb返回的都是浮點型,因此有可能返回INFINITY和NAN這兩個特殊值;而ilogb則返回的是整型,因此如果x是特殊的話那么將會返回FP_ILOGB0和FP_ILOGBNAN兩個值。

log2返回的是有可能帶小數(shù)的指數(shù),而logb和ilogb則返回的是一個不大于實際指數(shù)的整數(shù)。

絕對值函數(shù)

1. 取絕對值函數(shù):y = |x|extern?float?fabsf(float);

extern?double?fabs(double);

extern?long?double?fabsl(long?double);

冪函數(shù)

1. 平方根函數(shù):y = √xextern?float?sqrtf(float?x);

extern?double?sqrt(double?x);

extern?long?double?sqrtl(long?double?x);

2. 立方根函數(shù):?y = ?xextern?float?cbrtf(float?x);

extern?double?cbrt(double?x);

extern?long?double?cbrtl(long?double?x);

3. 冪函數(shù):z = x ^ yextern?float?powf(float?x,?float?y);

extern?double?pow(double?x,?double?y);

extern?long?double?powl(long?double?x,?long?double?y);

4. 歐幾里得距離函數(shù):?d =√x^2+y^2extern?float?hypotf(float?x,?float?y);

extern?double?hypot(double?x,?double?y);

extern?long?double?hypotl(long?double?x,?long?double?y);

這個函數(shù)可以用來求直角三角形的斜邊長度。

誤差函數(shù)

誤差函數(shù)主要用于概率論和偏微分方程中使用,具體參考誤差函數(shù)

1. 誤差函數(shù)extern?float?erff(float?x);

extern?double?erf(double?x);

extern?long?double?erfl(long?double?x);

2. 互補誤差函數(shù)extern?float?erfcf(float?x);

extern?double?erfc(double?x);

extern?long?double?erfcl(long?double?x);

伽瑪函數(shù)

1. 伽瑪函數(shù) :y = ????(x)extern?float?lgammaf(float?x);

extern?double?lgamma(double?x);

extern?long?double?lgammal(long?double?x);

2. 階乘函數(shù):y = (x-1)!extern?float?tgammaf(float?x);

extern?double?tgamma(double?x);

extern?long?double?tgammal(long?double?x);

伽瑪函數(shù)其實就是階乘在實數(shù)上的擴展,一般我們知道3! = 3*2*1 = 8。那么我們要求2.5!怎么辦,這時候就可以用這個函數(shù)來實現(xiàn)。這個函數(shù)也可以用來進行階乘計算。 注意這里是x-1后再計算的。

取整函數(shù)

1. 返回一個大于等于x的最小整數(shù)extern?float?ceilf(float?x);

extern?double?ceil(double?x);

extern?long?double?ceill(long?double?x);

舉例來說我們要對于一個負浮點數(shù)按0.5進行四舍五入處理:即當某個負數(shù)的小數(shù)部分大于等于0并且小于0.5時則舍棄掉小數(shù)部分,而當小數(shù)部分大于等于0.5并且小于1時則等于0.5。我們就可以用ceil函數(shù)來實現(xiàn)如下:double?y?=?ceil(x*0.5)/0.5;

2. 返回一個小于等于x的最大整數(shù)extern?float?floorf(float?x);

extern?double?floor(double?x);

extern?long?double?floorl(long?double?x);

舉例來說我們要對于一個正浮點數(shù)按0.5進行四舍五入處理:即當某個正數(shù)的小數(shù)部分大于等于0并且小于0.5時則舍棄掉小數(shù)部分,而當小數(shù)部分大于等于0.5并且小于1時則等于0.5。我們就可以用floor函數(shù)來實現(xiàn)如下:double?y?=?floor(x*0.5)/0.5;

3. 返回一個最接近x的整數(shù)extern?float?nearbyintf(float?x);

extern?double?nearbyint(double?x);

extern?long?double?nearbyintl(long?double?x);

extern?float?rintf(float?x);extern?double?rint(double?x);

extern?long?double?rintl(long?double?x);

//下面三個函數(shù)返回的是整數(shù)。

extern?long?int?lrintf(float?x);

extern?long?int?lrint(double?x);

extern?long?int?lrintl(long?double?x);

//下面三個函數(shù)是C99或者gnu99中的函數(shù)。

extern?long?long?int?llrintf(float?x);

extern?long?long?int?llrint(double?x);

extern?long?long?int?llrintl(long?double?x);

4. 對x進行四舍五入取整extern?float?roundf(float?x);

extern?double?round(double?x);

extern?long?double?roundl(long?double?x);

extern?long?int?lroundf(float?x);

extern?long?int?lround(double?x);

extern?long?int?lroundl(long?double?x);

//下面三個函數(shù)是C99或者gnu99中的函數(shù)。

extern?long?long?int?llroundf(float?x);

extern?long?long?int?llround(double?x);

extern?long?long?int?llroundl(long?double?x);

如果x是正數(shù),那么當小數(shù)部分小于0.5則返回的整數(shù)小于浮點數(shù),如果小數(shù)部分大于等于0.5則返回的整數(shù)大于浮點數(shù);如果x是負數(shù),那么當小數(shù)部分小于0.5則返回的整數(shù)大于浮點數(shù),如果小數(shù)部分大于等于0.5則返回的整數(shù)小于浮點數(shù)。

如果我們要實現(xiàn)保留N位小數(shù)的四舍五入時。我們可以用如下的方法實現(xiàn):double?y?=?round(x?*?pow(10,?N))?/?pow(10,?N)

數(shù)字拆分

1. 返回浮點數(shù)x的整數(shù)部分extern?float?truncf(float?x);

extern?double?trunc(double?x);

extern?long?double?truncl(long?double?x);

這個函數(shù)和floor函數(shù)的區(qū)別主要體現(xiàn)在負數(shù)上,對一個負數(shù)求floor則會返回一個小于等于負數(shù)的負整數(shù),而對一個負數(shù)求trunc則會返回一個大于等于負數(shù)的負整數(shù)。

如果我們要實現(xiàn)保留N位小數(shù)的截取時。我們可以用如下的方法實現(xiàn):double?y?=?trunc(x?*?pow(10,?N))?/?pow(10,?N)

2. 返回x/y的余數(shù)1:?z = mod(x, y)extern?float?fmodf(float?x,?float?y);

extern?double?fmod(double?x,?double?y);

extern?long?double?fmodl(long?double?x,?long?double?y);

函數(shù)返回值r = x - n*y, 其中n等于x/y的值截取的整數(shù)。

3. 返回x/y的余數(shù)2:?z = mod(x, y)extern?float?remainderf(float?x,?float?y);

extern?double?remainder(double?x,?double?y);

extern?long?double?remainderl(long?double?x,?long?double?y);

函數(shù)返回值r = x - n*y, 其中n等于x/y的值取最接近的整數(shù),如果有兩個數(shù)都接近x/y,那么n就取偶數(shù)。比如我們要求remainder(7,2)。因為7/2是3.5,按上面規(guī)則n就取4,因此最后的結(jié)果是r = 7 - 4*2 = -1。同樣我們可以得出remainder(7,3) == 7-2*3 == 1。從上面的描述可以看出fmod和remainder的區(qū)別主要在于x/y的整數(shù)部分的處理不一樣:前者是取x/y的整數(shù)來算余數(shù),而后者則取最接近x/y的整數(shù)來算余數(shù)。

4. 返回x/y的余數(shù)和整數(shù)商extern?float?remquof(float?x,?float?y?,?int?*quo);

extern?double?remquo(double?x,?double?y,?int?*quo);

extern?long?double?remquol(long?double?x,?long?double?y,?int?*?quo);

這個函數(shù)和remainder函數(shù)一樣,只不過會將整數(shù)商也返回給quo,也就是說r = x - n *y這個等式中,r作為函數(shù)的返回,而n則返回給quo。

5. 分解出x的整數(shù)和小數(shù)部分extern?float?modff(float?x,?float?p*);

extern?double?modf(double?x,?double?p*);

extern?long?double?modfl(long?double?x,?long?double?p*);

函數(shù)返回小數(shù)部分,整數(shù)部分存儲在p中。這里面返回值和p都和x具有相同的符號。

6. 分解出x的指數(shù)和尾數(shù)部分extern?float?frexpf(float?x,?int?*?p);

extern?double?frexp(double?x,?int?*?p);

extern?long?double?frexpl(long?double?x,?int?*?p);

函數(shù)返回尾數(shù)*符號部分,指數(shù)部分存儲在p中。需要明確的是如果浮點數(shù)x為0或者非規(guī)格化浮點數(shù)時按浮點數(shù)的定義格式返回尾數(shù)和指數(shù),而當x為規(guī)格化浮點數(shù)那么返回的值的區(qū)間是[0.5, 1)。這里的返回值和指數(shù)值p和上面介紹的規(guī)格化浮點數(shù)格式:符號 * (1.尾數(shù)) * 2^指數(shù)有差異。因為按照定義返回的尾數(shù)部分應(yīng)該是1.xxx,但是這里的返回值卻是[0.5, 1)。其實這并不矛盾,只是函數(shù)對返回的值做了特殊處理:因為一個正浮點數(shù)可以表示為:1.m * 2^e ==> (2^0 + 0.m) * 2^e ==> (2^0 / 2 + 0.m / 2) *2^(e+1) =>(0.5 + 0.m/2) *2^(e+1)。因此frexp函數(shù)返回的真實值是: 尾數(shù)除以2,而p存儲的是:指數(shù)+1

下面函數(shù)使用的一些例子:int?p1?=?0;???double?y1?=?frexp(16.0,?&p);?//y1=0.5,?p=?5

int?p2?=?0;??double?y2?=?frexp(1.0,?&p);?//y2=0.5,?p?=?1

int?p3?=?0;??double?y3?=?frexp(0.0,?&p);?//y3=0,?p?=?0

這個函數(shù)和上面的ldexp函數(shù)為互逆函數(shù)。要詳細的了解浮點數(shù)存儲格式請參考

符號改變

1. 將y的符號賦值給x并返回具有和y相同符號的x值extern?float?copysignf(float?x,?float?y);

extern?double?copysign(double?x,?double?y);

extern?long?double?copysignl(long?double?x,?long?double?y);

舉例如下:copysign(10.0,?9.0)??==?10;

copysign(-10.0,?-9.0)?==?-10;

copysign(-10.0,?9.0)?==?10;

copysign(10.0,?-9.0)?==?-10;

這個函數(shù)的作用是實現(xiàn)符號的賦值,有就是將y的符號賦值給x。

無效數(shù)字定義

1.生成一個quient NAN浮點數(shù)extern?float?nanf(const?char?*tagp);

extern?double?nan(const?char?*tagp);

extern?long?double?nanl(const?char?*tagp);

前面我有介紹了浮點數(shù)里面有兩個特殊的值:無窮INFINITY和非法NAN,既然這兩個數(shù)字都可以用浮點數(shù)來描述,那么他就肯定也有對應(yīng)的存儲格式。我們知道浮點數(shù)的格式為:符號*尾數(shù)*2^指數(shù)。在IEEE754標準中就對無窮和非法這兩種特殊的數(shù)進行了定義:當浮點數(shù)中的指數(shù)部分的二進制位全為1。而尾數(shù)部分的二進制位全為0時則表示的浮點數(shù)是無窮INFINITY,如果符號位為0則表示正無窮大,而符號位為1則表示負無窮大。

當浮點數(shù)中的指數(shù)部分的二進制位全為1。而尾數(shù)部分的二進制位不全為0時則表示的浮點數(shù)是非法數(shù)字NAN,或者表示為未定義的數(shù)字。

從上面的對NAN的定義可以得出非法數(shù)字并不是一個具體的數(shù)字而是一類數(shù)字,因此對兩個為NAN的浮點數(shù)字并不能用等號來比較。以32位IEEE單精度浮點數(shù)的NAN為例,按位表示即:S111 1111 1AXX XXXX XXXX XXXX XXXX XXXX,其中的S是符號位,而符號位后面的指數(shù)位為8個1表示這個數(shù)字是一個特殊的浮點數(shù),剩余的A和X則組成為了尾數(shù)部分,因為是NAN?所以我們要求A和X這些位中至少有一個是1。在IEEE 754-2008標準中,又對NAN的類型進行了細分:如果A = 1,則該數(shù)是quiet NAN。也就是quiet NAN中尾數(shù)的最高位為1。

如果A為零、其余X部分非零,則是signaling NAN。

區(qū)分兩種NAN的目的是為了更好的對浮點數(shù)進行處理。一般我們將signaling NAN來表示為某個數(shù)字未初始化,而將quiet NAN則用來表示浮點運算的結(jié)果出現(xiàn)了某類異常,比如0除異常,比如負數(shù)開根異常等等。既然quiet NAN可以用來對無效數(shù)字進行分類,也就是說我們可以構(gòu)建出一個有類別標志的quiet NAN。因此nan函數(shù)就是一個專門構(gòu)建具有無效類別的NAN函數(shù)(繞了這么多終于說到點子上了)。nan函數(shù)中的tagp參數(shù)就是用來指定非法數(shù)字中的類別,雖然參數(shù)類型是字符串,但是要求里面的值必須是整數(shù)或者空字符串,而且系統(tǒng)在構(gòu)造一個quiet NAN時會將tagp所表示的整數(shù)放在除A外的其他尾數(shù)位上。下面是使用nan函數(shù)的例子:float?f1?=?NAN;???????????//0b01111111110000000000000000000000

float?f2?=?nanf("");??????//0b01111111110000000000000000000000

float?f3?=?nanf("123");???//0b01111111110000000000000001111011

float?f4?=?nanf("456");???//0b01111111110000000000000111001000

float?f5?=?nanf("abc");???//0b01111111110000000000000000000000

具體操作時我們可以用如下來方法來處理各種異常情況://定義部分:float??testfn(){

//有異常時根據(jù)不同的情況返回不同的nan。

if?(異常1)

return?nan("100");

else?if?(異常2)

return?nan("200");

else

return?正常數(shù)字;

}

//調(diào)用部分:

float?ret?=?testfn();

if?(isnan(ret))

{??????//取非法數(shù)字的錯誤標志部分

int?exceptionType?=?ret?&?0x3FFFFF;

if?(exceptionType?==?100)

{

}

else?if?(exceptionType?==?200)

{

}

}

else

{

//正常處理。

}

有一個地方疑惑的是為什么NAN定義默認值是一個quiet NAN而不是signaling NAN

遞增函數(shù)

1. 返回x在y方向上的下一個可表示的浮點數(shù)。extern?float?nextafterf(float?x,?float?y);

extern?double?nextafter(double?x,?double?y);

extern?long?double?nextafterl(long?double?x,?long?double?y);

extern?double?nexttoward(double?x,?long?double?y);

extern?float?nexttowardf(float?x,?long?double?y);

extern?long?double?nexttowardl(long?double?x,?long?double?y);

如果x等于y則返回x。這個函數(shù)主要用來實現(xiàn)那些需要高精度增量循環(huán)的處理邏輯。也就是說如果對浮點數(shù)進行for循環(huán)處理時,這個函數(shù)可以用來實現(xiàn)最小的浮點數(shù)可表示的數(shù)字的增量。比如下面的代碼:for?(double?x?=?0.1;?x?

{?????????//...

}

注意這里是下一個可表示的浮點數(shù),也就是說當x為0而y為1時,那么返回的值將是最小的非常規(guī)浮點數(shù);而如果x為1而y為2時,那么返回的值將是1+DBL_MIN(or FLT_MIN). 下面是具體的示例代碼://?0.0f?==?0b00000000000000000000000000000000

float?a?=?nextafterf(0.0f,?1.0f);???//a?==?0b00000000000000000000000000000001

//?FLT_MIN?==???0b00000000100000000000000000000000

float?b?=?nextafterf(FLT_MIN,?1.0f);?//?b?=?0b00000000100000000000000000000001

//?1.0f?==?0b00111111100000000000000000000001

float?c?=?nextafterf(1.0f,?1.1f);?//?c?=?0b00111111100000000000000000000001

比較函數(shù)

1. 返回x減去y的差如果x>y,否則返回0extern?float?fdimf(float?x,?float?y);

extern?double?fdim(double?x,?double?y);

extern?long?double?fdiml(long?double?x,?long?double?y);

這個函數(shù)可以用來求兩個數(shù)的差,并且保證不會出現(xiàn)負數(shù)。下面是使用的例子:double?a?=?fdim(5.0,?3.0);???//2.0

double?b?=?fdim(5.0,?5.0);???//0.0

double?c?=?fdim(5.0,?6.0);???//0.0

2. 返回x和y中大的數(shù)字:?z = max(x,y)extern?float?fmaxf(float?x,?float?x);

extern?double?fmax(double?x,?double?x);

extern?long?double?fmaxl(long?double?x,?long?double?x);

3. 返回x和y中小的數(shù)字:?z = min(x,y)extern?float?fminf(float?x,?float?y);

extern?double?fmin(double?x,?double?y);

extern?long?double?fminl(long?double?x,?long?double?y);

浮點乘加運算

1. 浮點乘加運算:w = x*y + zextern?float?fmaf(float?x,?float?y,?float?z);

extern?double?fma(double?x,?double?y,?double?z);

extern?long?double?fmal(long?double?x,?long?double?y,?long?double?z);

這個函數(shù)返回x*y+z的結(jié)果,而且會保證中間計算不會丟失精度。這個函數(shù)會比直接用x*y+z要快,因為CPU中專門提供了一個用于浮點數(shù)乘加的指令FMA。具體情況請參考關(guān)于浮點乘加器方面的資料和應(yīng)用。

結(jié)語

最后歡迎大家訪問我的github站點?多多點贊,多多支持!

參考文章:

總結(jié)

以上是生活随笔為你收集整理的c语言定义小数无穷小,OC中常用的数学函数以及浮点处理函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。