浮點數和定點數的相互轉換(浮點數量化爲定點)

1. 這篇博客將要討論什麼?

說來慚愧,作爲計算機科班出身的人,計算機基礎知識掌握並不紮實,這裏的基礎指的是計算機體系結構中的內容,諸如數據的表示和處理,如float的表示和運算等。看《CSAPP》方知人家老外把這個東西當成重中之重,大量詳細的原理介紹,並配套大量例題。當初本科學的時候,很簡單的瞭解了下概念而已,所以應該直接將《CSAPP》當做教材來用,裏面習題全做,這樣CS出來的基本知識將掌握的很紮實。

學藝不精的後果就在於:學而不思則罔。聖人太厲害了,總結得很到位。比如最近項目中涉及到浮點和定點的轉換,自己就有點蒙,邊看邊實驗,還算理解了,作文以記之。

一直以來,程序中接觸的數據類型都是int整型,char字符型,float單精度浮點型,double雙精度浮點型。看到浮點和定點一直不知道如何劃分這個概念的範疇。以爲浮點就是float表示小數,定點就是int可表示整數而已。經過學習明白了顯然是錯誤的。應該是這樣劃分的:

  • 浮點:小數點非固定的數,可表示數據範圍較廣,整數,小數都可表示。包含float,double;
  • 定點:小數點固定,可表示整數,小數。int本質是小數點位於末尾的32位定點數而已;

有了這個認識,後面的討論就可以開始了。

2. 浮點數的表示法

浮點數以float爲例討論。

2.1 IEEE 754標準

規定浮點數格式爲:V=(1)s×M×2EV = (-1)^s×M×2^E

  • s表示符號位,當s=0,V爲正數;當s=1,V爲負數
  • M表示尾數,2>M>=12>M>=1
  • E表示階碼

將其封裝到32位的字中:

符號位 階碼 尾數
1 8 23

根據32位數計算爲十進制:V=(1)s×(1.M)×2(E127)V = (-1)^s×(1.M)×2^{(E-127)}

可以得出以下結論:

  • 浮點數表示比整型那些更爲複雜。如int中0…01000表示8,0…01001表示9,而浮點不能這樣簡單。
  • 浮點數不能移位。因爲各個位有特殊含義。像int數乘2可以左移1位實現。

2.2 浮點數的“浮”字體現在哪裏?

我們說浮點數的小數點不是固定的,是浮動的,那麼如何理解?通過例子可直觀體驗。

符號 階碼 尾數
0 0111 001

這個浮點數表示十進制的1.125

符號 階碼 尾數
0 0111 010

若階碼不變,尾數加1,則表示十進制的1.25

符號 階碼 尾數
0 1000 001

若尾數不變,階碼加1,則表示十進制的2.25

3. 定點數的表示法

對於計算機來說,浮點定點的概念是看不見的,因爲它只能看到:0…00001110,至於它表示多少,是邏輯層面的設置。你如果讓它是int那就按照int表示法對每個位賦予意義,如果你讓它是float就按照float表示法賦予意義。

對於0001110000011100表示的定點數:

  • 如果我們設定小數點是位於最後一位的,即00011100.00011100.則其表示28
  • 若設定小數點位於後三位的,即00011.10000011.100則其表示3.50
  • 若設定小數點位於後四位的,即0001.11000001.1100則其表示1.75

可以看到:

  • 小數位數越多,表示的精度越高。若小數點後有n位,則其表示的最大精度爲1/(2n)1/(2^n)
  • 整數位數越多,可表示的最大值越大。

以8位爲例,最高位爲符號位:

  • 若整數位佔4位,小數位佔3位,則其最大精度爲0.125,最大值爲15.875
  • 若整數位佔5位,小數位佔2位,則其最大精度爲0.250,最大值爲31.750
  • 若整數位佔6位,小數位佔1位,則其最大精度爲0.500,最大值爲63.500
  • 若整數位佔7位,小數位佔0位,則其最大精度爲1.000,最大值爲127

4. 浮點數 & 定點數

4.1 爲何要把浮點數轉換爲定點數呢?

這來源於項目中神經網絡的需求,網絡中大量的參數,如果全部用F32表示,一是佔用空間大,二是讀取效率不高。

如果我們可以將某些浮點數轉換爲定點數表示,在接受精度損失的前提下,每次就可以讀取多個進行運行,可顯著提高運算效率。

舉例來說,我們用8位定點數,1個符號位,4個整數位,3個小數位,則其可表示範圍是-16.00~15.875,最大精度0.125。

有幾個浮點數:0.145,1.231,2.364,7.512,每個需要32bit表示。

如果我們將每個量化成一個8位定點數,比如通過某種方法得到:1,10,19,60

此時每個數需要8bit表示。那麼讀一個浮點數,可以同時讀4個定點數,且計算效率可以提高。當然這樣做是有風險的:

  • 損失精度,比如再將上述定點數轉化爲浮點數:0.125,1.250, 2.375,7.500;
  • 定點數表示範圍有限,加法有可能會溢出,需要拿int16或int32來暫存中間結果;

4.2 如何將浮點數轉換爲定點數?

我們用8位定點數,1個符號位,4個整數位,3個小數位。這個3稱爲量化係數。該過程稱爲量化。

(我們總是將非離散值量化到離散值空間,處理更爲簡單)

int8=float32    2(3)int8 = float32 \,\,* \,\, 2^{(3)}

如:int810=float321.231    2(3)int8(10) = float32(1.231) \,\,* \,\, 2^{(3)}

4.3 如何將定點數轉換爲浮點數?

該過程稱爲反量化。

float32=int8  /  2(3)float32 = int8 \,\,/ \,\, 2^{(3)}

如:float321.250=int810  /  2(3)float32(1.250) = int8(10) \,\,/ \,\, 2^{(3)}

4.4 note

可以這樣理解:量化係數 nn 決定了我們邏輯上認爲01序列中可表示的單位值 1/(2n)1/{(2^n)},CPU讀取的數字表示有多少份單位值。

舉例來說,對於固定的01序列值:00111000

量化係數 CPU讀取值 單位值 表示邏輯值
3 28 0.125 3.5
2 28 0.250 7.0

同樣的int8數,因爲量化係數的不同,代表着不同的f32值。

還有個note:

  • 定點數加減時需要量化係數相同,其值有可能溢出,需要更大定點數來暫存中間值;
  • 兩個定點數乘法後如果需要轉化爲f32,則反量化係數變爲2n2*n

5. 總結

可以看到:

  • 浮點數和定點數的轉換是一種映射。將較爲密集的數據空間(F32)映射到較爲稀疏的空間(int8);
  • 定點數的小數點實際中是沒有的,這只是我們邏輯上的一種設定。01序列是一樣的,CPU讀取都是相同的,因爲我們邏輯上小數點的不同位置,我們認爲它代表的值是不同的;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章