同樣是占32個坑,憑啥你float就比int的范圍更大?


原文出處:https://zhuanlan.zhihu.com/p/84453627?from_voters_page=true

ok,這里先說明一下,假設是在32位的機器上,int是32位。而float使用的是IEEE 754標准的單精度浮點數格式也是占用32位。

這時候float和int都是占用32位,占用同樣的空間,但float范圍是更大的,那我們為啥還要int呢?為啥不節省空間,只用float?我們來一探究竟!他們在計算機的大腦里是如何記憶的?

1、int對32個坑是如何使用的?

(實名吐槽知乎,居然沒有表格。。。)

int類型的使用方法,大多學過計算機的,應該都是非常清楚的。二進制存儲即可。

例1:請寫出165(10進制)使用32位int型存儲在計算機中的形式。

10進制轉換為2進制,我個人喜歡先轉為16進制,再寫成2進制。

如下: [公式]

那么165在32位int型中是這樣存儲的(中間的0,我省略了):

165在計算機中的int存儲

非常簡單明了,好理解。把10進制轉換2進制,直接存進去就ok,前面空位補0。

例2:請寫出-165(10進制)使用32位int型存儲在計算機中的形式。

這是一個負數,按照慣例int型首位為符號位。0表示在正數,1表示負數。

如下: [公式]

但在計算機中,負數存儲的是補碼,不是原碼。

他們之間按照如下轉換:

原碼:1000 0000 1010 0101

反碼:1111 1111 0101 1010 (除了符號位,其它取反)

補碼:1111 1111 0101 1011 (在反碼的基礎上加1即可)

那么-165在32位int型中是這樣存儲的(中間的1,我省略了):

-165在計算機中的int存儲

比正數復雜了一點,但是還是可以很容易算出來的。

問題來了?為啥負數要用補碼?這不是挑事嗎?原碼不好嗎?

原因之一在於,我們計算: [公式] ,在計算機中存儲的是二進制,

如果使用原碼進行計算,需要單獨把符號位拿出來,再做減法運算,而把符號位區分出來是需要額外的硬件電路支撐的,這很不方便。

如果使用補碼,如下所示(這里按照16位進行舉例):

0000 0000 1010 0101 + 1111 1111 0101 1011=0000 0000 0000 0000;

使用補碼參與運算后,無需再管符號位,可以讓符號位直接參與運算。這就是使用補碼的最大的好處。到這里大家有沒有發現,int型的這種存儲方案是沒有考慮小數的,所以這是整型的。關於int型的存儲,不再贅述,整體來說還是清晰明了的一種方案。


2、float對32個坑是如何使用的?

同樣也是占用32個坑,float型的范圍比int就大很多,而且還能表示小數,那么它到底是如何利用這32個坑的呢?

例3:請寫出165.25(10進制)使用float型存儲在計算機中的形式。

同樣我們還是先轉換為2進制:[公式] 1010 0101 . 0100

那么如何把上面的二進制小數存到32個坑里呢?

在填坑之前,我們先要規范二進制小數的表示形式,就和我們的科學計數法一樣的道理。

(就像 [公式] 要寫成 [公式] 這個樣子,把所有的小數換成統一的格式)

IEEE754標准做了這樣的規定:當尾數(小數)不為0時,尾數域的最高有效位為1,這稱為浮點數的規格化。

例如: [公式]

規格化后的二進制小數,有了統一的規格,可以發現這樣規格化之后,我們只需要存儲一個尾數(即小數部分,整數部分恆為1)和指數部分。

IEEE754標准把float型的32個坑做了如下划分:

其中包含了1位符號位S,8位階碼E和23位尾數M。

[公式] ,要存儲這個二進制小數;

首先符號位S,0表示正數,1表示負數。S=0;

再寫出尾數M,即:M=0100 1010 1000 0000 0000 000;

然后算出階碼E,這里指數為:e=7=0000 0111,根據標准要求,E=e+127;

即:E=7+127=134=1000 0110;

那么把這三個數都填進坑里,就ok啦。

165.25在計算機中的float儲存

這個計算過程稍微復雜點,但也還可以手算出來。

但是問題又來了:

1、浮點數的表示范圍有多大?

2、為什么要用指數加上127,才是階碼E,而不是直接用指數存進去?

3、這個過程可以看出float有效位是尾數M加1也就是24位,階碼E只是我們規范科學計數法記錄指數的,但int有效位是32位,float實際有效位比int少,那么在相互轉換的過程中會出現什么問題?

我依次解釋這3個問題:

1、浮點數的表示范圍有多大?

float型定義的正無窮大

float型定義的負無窮小

可以得出當E= 1111 1111時,指數為255-127=128,但這並不是表示這個數是: [公式] ,在IEEE754把這種情況定義為無窮大,此時尾數必須全部為0,不能有其他值,否則就認為無效數字。

那么除了無窮大這個特殊的、人為定義的情況,float型能表示的最大的正整數是多少?最小的負整數是多少?當E= 1111 1111時,是IEEE754定義的特殊值即為無窮大,那么除此之外的最大值就是:E= 1111 1110,M也取最大值,即得到如下結果:

float型能存儲的最大正整數

此時階碼E為254,指數即為e=254-127=127。這個數即為:

[公式] ;

對於尾數我們可以換一個寫法:

1.1111 1111 1111 1111 1111 111=10-0.0000 0000 0000 0000 0000 001

這樣尾數可以寫成: [公式] ;

那么float能夠表示的最大正整數就是: [公式] ,即為 [公式] 。

那么float能夠表示的最大負整數就是: [公式] 。

2、為什么要用指數加上127,才是階碼E,而不是直接用指數存進去?

這就很容易說明了,我們舉個例子:

例4:請寫出0.75(10進制)使用float型存儲在計算機中的形式。

寫成二進制:[公式] 。再寫成規划化的計數法: [公式] ;

發現問題了沒有?這次的指數是個負數啦,而我們希望存儲到機器里的階碼永遠都是正值,因為我們不希望再浪費一個坑去保存階碼的正負號,於是乎,干脆把指數加上127,而指數能取到的最小值就是-127,這樣就可以保證階碼E永遠都是正數啦,我們就不用再考慮指數正負號的問題了。

E=-1+127=126=0111 1110;

M=1000 0000 0000 0000 0000 000;

0.75在計算機中的float儲存

3、這個過程可以看出float有效位是尾數M加1也就是24位,階碼E只是我們用於規范科學計數法記錄指數的,但int有效位是32位,float實際有效位比int少,那么在相互轉換的過程中會出現什么問題?

通過問題1知道,float型的表示范圍是比int大很多的,但有效位確實只有24位。既然float范圍大,那么所有的int型都是可以轉換為float型的,這是不會產生溢出報錯的。但因為int型有效位是32位,是比float型的24位大的,是有可能發生舍入的,即當一個int型數字,轉成float型后,可能就不再是原本數字了,損失了一定的精度。

例如2進制int型正數:0111 1111 1111 1111 1111 1111 1111 1111;

寫成科學計數法即為: [公式]

小數點后面有30個1,但是我們知道float種尾數M只有23個坑。

則轉化為float型后,階碼E=30+127=157=1001 1101

可以發現,我們對原int型中存儲的數字只保留了小數點后23個1,而后面7個,直接忽視了,這就是發生了舍入。

如果既要范圍大,還要保留精度,那就上雙精度浮點型double,double型的存儲規則和float型是十分類似的。double型有64個坑位,包括了1個符號位S,11個階碼位E和52個尾數位M。所以double的有效位有53位,可以完整保留int。

ok,同樣是占32個坑,那憑啥你float就比int的范圍更大?因為float型雖然范圍大,但是精度不足啊!所以各有千秋哦。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM