C语言的int, float,double相互转化 (从本质上理解可能的问题)
從學(xué)了C語(yǔ)言之后,一直習(xí)慣于C/C++任意的強(qiáng)制轉(zhuǎn)化,但是C語(yǔ)言的強(qiáng)制轉(zhuǎn)化卻總是帶來(lái)意想不到的后果,在這里,我將從int,float,double的本質(zhì)上講解這些可能出現(xiàn)的問題以及解決辦法,在下面你將看到:
OK,現(xiàn)在好戲開始。
- int
- unsigned int: unsigned int所進(jìn)行的是模數(shù)計(jì)算,就是正常的二進(jìn)制相加減,計(jì)算方法和十進(jìn)制加減并無(wú)區(qū)別,但是unsigned int有著正溢出和負(fù)溢出的問題,如下圖計(jì)算所示:
這一點(diǎn)是我們需要注意的地方。 - int:int所使用的是32位補(bǔ)碼,關(guān)于補(bǔ)碼的運(yùn)算,在這里就不贅述了,大部分計(jì)算機(jī)導(dǎo)論的書籍都有相關(guān)說(shuō)明。
- 接下來(lái),要說(shuō)的就是unsigned int和int的相互轉(zhuǎn)化,請(qǐng)看如下代碼:
- unsigned int: unsigned int所進(jìn)行的是模數(shù)計(jì)算,就是正常的二進(jìn)制相加減,計(jì)算方法和十進(jìn)制加減并無(wú)區(qū)別,但是unsigned int有著正溢出和負(fù)溢出的問題,如下圖計(jì)算所示:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
這段代碼計(jì)算一個(gè)數(shù)組所有元素之和,看起來(lái)似乎沒什么問題。但是當(dāng)你的數(shù)組為空的時(shí)候,length輸入0之后,卻返回一個(gè)存儲(chǔ)器錯(cuò)誤,這是為什么呢?請(qǐng)看上文關(guān)于unsigned int計(jì)算的式子,length是unsigned int 類型,進(jìn)行的是模數(shù)運(yùn)算,只代表正數(shù),如果出先了0000000(這里有32個(gè)0)-00000..01(31個(gè)0,1個(gè)1)=111…11111(32個(gè)1)=UMAX。一個(gè)本該為-1的數(shù)變成了無(wú)符號(hào)數(shù)最大值,當(dāng)然,當(dāng)i取任何不為0的數(shù)都發(fā)生了非法訪問,自然出現(xiàn)了存儲(chǔ)器錯(cuò)誤,并且任何數(shù)都小于UMAX,就會(huì)出現(xiàn)判別式永遠(yuǎn)為真,出現(xiàn)死循環(huán)。解決這個(gè)問題的方法有兩種,做一個(gè)判斷,當(dāng)傳入length<1,直接返回0.或者,在之前就將length轉(zhuǎn)化為int。
- 浮點(diǎn)數(shù)(float,double的理解)
- 什么是定點(diǎn)數(shù),定點(diǎn)數(shù)有什么缺點(diǎn):
我們用二進(jìn)制數(shù)表示整數(shù),我們也想用二進(jìn)制表示小數(shù)。自然而然,我們會(huì)像十進(jìn)制的小數(shù)一樣,在二進(jìn)制上加上小數(shù)點(diǎn),例如1.001111122,
但是這樣的二進(jìn)制會(huì)出現(xiàn)什么樣的問題呢?請(qǐng)看下面的二進(jìn)制小數(shù)
- 什么是定點(diǎn)數(shù),定點(diǎn)數(shù)有什么缺點(diǎn):
| 5 | 3/4 | 101.1122 |
大家觀察一下,二進(jìn)制小數(shù)有什么特點(diǎn)。
只能準(zhǔn)確的表示x/2kx/2k只能近似,請(qǐng)看下面的小數(shù)
| 1/3 | 0.01010101[01]…22 |
[0011]表示無(wú)限循環(huán)小數(shù)
為什么會(huì)出現(xiàn)這樣的計(jì)算結(jié)果,請(qǐng)看下面1/3 和 1/5是如何計(jì)算的。
1/5就復(fù)雜了點(diǎn)
可見,當(dāng)小數(shù)不能表示為
s:表示符號(hào)位,只用一個(gè)bit表示
M:表示尾數(shù)(significand)(frac)也表示小數(shù)位,即能準(zhǔn)確表示小數(shù)位
E:表示指數(shù)位,簡(jiǎn)單來(lái)說(shuō)就是位數(shù)的多大。
那么,我們來(lái)看一下,我們最常用的float,double是怎么組成的:
明顯的看出,float有8位指數(shù)位,23位尾數(shù)位。指數(shù)最大可表示的范圍為-127~126,但浮點(diǎn)數(shù)的指數(shù)計(jì)算有一點(diǎn)技巧要用到:E-Bias。
下面是浮點(diǎn)數(shù)所表示的一個(gè)范圍:
大家可以清楚的看到浮點(diǎn)數(shù)隨著大小的不同被分成好幾種,接近0的被稱為Denormalized,比較大的數(shù)字被分為Infinity,接下來(lái)介紹這幾種數(shù)字的特征:
Normalized:這是最常見的一種情況,指數(shù)位EXP不為0(不小),EXP不全為1(不大)。此時(shí),階碼(這個(gè)2EE-1,k表示指數(shù)位的位數(shù),float單精度即32位浮點(diǎn)為127,double雙精度為1023。故float單精度的E范圍為-126~127,對(duì)于雙精度為-1022~+1023。
而對(duì)于尾數(shù)位,即小數(shù)位:相當(dāng)于得到的數(shù)為1.M(M表示尾數(shù)位)
下面就到了重點(diǎn)了,這也是浮點(diǎn)數(shù)經(jīng)常被大家忽略的地方。
Denormalized:當(dāng)階數(shù)E全為0的時(shí)候,被稱為Denormalized,那么它的指數(shù)位就變成了E=1-Bias, 之所以不用-Bias,而用1-Bias,是為了實(shí)現(xiàn)與Normalized的數(shù)實(shí)現(xiàn)完美過渡,具體如何過渡的圖片會(huì)在下面給出。
而Denormalized的尾數(shù)有什么特點(diǎn)呢:如果frac為0,說(shuō)明該數(shù)為0,但是不知道是+0還是-0。因?yàn)?#xff0c;前面的符號(hào)位未知。如果frac不為0的話,那么實(shí)際的數(shù)字表示為0.M(M為尾數(shù)位),記住,此時(shí)前面是0.,因?yàn)橹挥惺?.最終才能接近0
Infinity:當(dāng)指數(shù)位全為1,frac尾數(shù)位為0的時(shí)候表示Infinity(可以表示無(wú)窮大),分別取符號(hào)位為1或者0,表示正無(wú)窮或負(fù)無(wú)窮。可以滿足Infinity相乘或除,表示溢出。
NaN:not a number,即指數(shù)位全為1,frac尾數(shù)位不全為0.
一張圖可以表示Normailized,Denormalized,Infinity,NaN
這張圖說(shuō)明,從Denormalized到NaN有什么變化:
可以看到在Denormalize使用E=1-Bias,并且M前取0,實(shí)現(xiàn)了從Largest denorm到Smallest norm完美過渡。
- 浮點(diǎn)數(shù)的rounding
上文提到無(wú)論是定點(diǎn)數(shù)還是浮點(diǎn)數(shù)都只能表示有限的位數(shù),那么舍入就顯的是一個(gè)很重要的環(huán)節(jié)了。浮點(diǎn)數(shù)采取的舍入方法,小于一半的向下舍入,大于一半的向上舍入,在中間的,close to even(向偶數(shù)舍入),下面是幾個(gè)二進(jìn)制例子:
Format A:
There are k=3 exponent bits. The exponent bias is 3.
There are n=4 fraction bits.
Format B:
There are k=4 exponent bits. The exponent bias is 7.
There are n=3 fraction bits.
要求給出A,將A轉(zhuǎn)化為B
前一半為A,后一半為B
| 0110000 | 1 | 0111000 | 1 |
| 1011110 | 712712 |
可以看出第二,三,四的問題的關(guān)鍵在于進(jìn)位
三的A為:0.11001,即到B先轉(zhuǎn)化為1.1001,明顯B的frac只有三位,所有根據(jù)close to even,需要接近偶數(shù),所以,round down:1.100,符合。
比較有問題的是最后一個(gè):000 0001 。首先,000說(shuō)明是Denormalize,則該數(shù)表示為0.0001*2?2?2,由于B是4位exp,所以不會(huì)是最小的數(shù),所以由Denormalize->Normalize,答案也為1/64
為什么要選擇,close to even呢?如果全部的數(shù)字都為0.01要精確到小數(shù)點(diǎn)后一位的話,如果是四舍五入,那么最后的誤差將是0.01*n,但如果是close to even的,認(rèn)為偶數(shù)和奇數(shù)是等概率出現(xiàn),就很小的避免誤差往一邊倒的情況。
- 浮點(diǎn)數(shù)的計(jì)算
首先先來(lái)兩個(gè)公式
x+ff)
但是3.14+(1e10-1e10)=3.14
le20*(le20-le20)=0.0
le20*le20-le20*le20=NaN,由于溢出的關(guān)系,可見在數(shù)字大的情況下不滿足加法結(jié)合律和乘法分配律
最后,來(lái)看看double,float和int相互轉(zhuǎn)化可能的問題
判斷以下式子是否正確:
A.正確,因?yàn)閐ouble的frac為32位和int相同,不會(huì)丟失信息。
B.錯(cuò)誤,因?yàn)閒loat的frac為23位小于int,會(huì)丟失信息。
C.錯(cuò)誤。double比f(wàn)loat精度高。從double轉(zhuǎn)float會(huì)丟失信息。
D.正確。
E.正確。符號(hào)數(shù)正負(fù)轉(zhuǎn)化只取決于符號(hào)位。
F.正確。浮點(diǎn)數(shù)在進(jìn)行運(yùn)算的時(shí)候會(huì)全部轉(zhuǎn)化為浮點(diǎn)數(shù)。
G.正確。
H.錯(cuò)誤。如果f+d溢出,結(jié)果為0.
總結(jié)
以上是生活随笔為你收集整理的C语言的int, float,double相互转化 (从本质上理解可能的问题)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Sensor]--BMI160-加速度
- 下一篇: 十分钟读懂『卡尔曼滤波算法』