C語言_浮點數_IEEE 754標準_單片機

目錄

IEEE 754標準

float的範圍

float精度

float小數

讀取小數存儲的原始值(舉例)


 

IEEE 754標準

IEEE-754 標準浮點格式

浮點格式可分爲符號位s,指數位e以及尾數位f三部分。 
其中真實的指數E相對於實際的指數有一個偏移量,所以E的值應該爲e-Bias,Bias即爲指數偏移量。這樣做的好處是便於使用無符號數來代替有符號的真實指數。尾數f字段代表純粹的小數,它的左側即爲小數點的位置。規格化數的隱藏位默認值爲1,不在格式中表達。

在IEEE-754 標準下,浮點數一共分爲:

  • NaN:即Not a Number。非數的指數位全部爲1 同時尾數位不全爲0。在此前提下,根據尾數位首位是否爲1,NaN 還可以分爲SNaN 和QNaN 兩類。前者參與運算時將會發生異常。
  • 無窮數:指數位全部爲1 同時尾數位全爲0。大。
  • 規格化數:指數位不全爲1 同時尾不全爲0。此時浮點數的隱含位有效,其值爲1。
  • 非規格化數:指數位全爲0 且尾數位不全爲0。此時隱含位有效,值爲0。另外需要注意,以單精度時爲例,真實指數E 並非0-127=-127,而是-126,這樣一來就與規格化下最小真實指數E=1-127=-126 達成統一,形成過度。非規格化數隱函數表示爲了,此時表示的數據更小,提高了精度
  • 0 :指數位與尾數位都全爲0,根據符號位決定正負。

 

float的範圍

注意:指數的範圍是-126~127,不是我們認爲的-127~128 這個是IEEE-754標準中定義的。

正數最大值如下:

高地址----------------------------->低​地址

0 (1111 1110)( 111 1111 1111 1111 1111 1111)

float最大爲(2-2^-23)*2^127= 3.4028234663852886*10^38

當我們令指數位爲:1111 1110 =254 (此處不能是1111 1111=255,此時是NaN)則指數爲254-127=127

尾數位全爲1,則最大數爲1.11111111111111111111111*2^127=(2-2^-23)*2^127=3.4028234663852886*10^38,正規格化數中的最大。1.111 1111 1111 1111 1111 1111+0.000 0000 0000 0000 0000 0001=2,0.000 0000 0000 0000 0000 0001=2^-23

當符號位爲1時

高地址----------------------------->低​地址

1(1111 1110)( 111 1111 1111 1111 1111 1111)

表示-3.4028234663852886*10^38

所以範圍是-3.4028234663852886*10^38 到 3.4028234663852886*10^38

 float最小值(除0以外的最小值)

高地址----------------------------->低​地址

0 (0000 0001)(000 0000 0000 0000 0000 0001)

當我們令指數位爲:0000 0001 =1(此處不能是0000 0000=0,指數全零是非規格化數)則指數爲1-127=126

爲:1.0000 0000 0000 0000 0000 001*2^-126= 1.1754944909521339e-038

 

float精度

float 類型的數據精度取決於尾數,首先是在不考慮指數的情況下23位尾數能表示的範圍是[0, 2^23−1],實際上尾數位前面還隱含了一個"1",所以應該是一共24位數字,所能表示的範圍是[0, 2^24-1](因爲隱含位默認是"1",所以表示的數最小是1不是0),看到這24位能表示的最大數字爲2^{24}-1,換算成10進制就是16777215,那麼[0, 16777215]都是能精確表示的

16777215 這個數字可以寫成1.1111111 11111111 1111111 * 2^{23},所以這個數可以精確表示,然後考慮更大的數16777216,因爲正好是2的整數次冪,可以表示1.0000000 00000000 00000000 * 2^{24}所以這個數也可以精確表示,在考慮更大的數字16777217,這個數字如果寫成上面的表示方法應該是 1.0000000 00000000 00000000 1 * 2^{24},但是這時你會發現,小數點後尾數位已經是24位了,23位的存儲空間已經無法精確存儲,這時浮點數的精度問題也就是出現了。

看到這裏發現 16777216 貌似是一個邊界,超過這個數的數字開始不能精確表示了,那是不是所有大於16777216的數字都不能精確表示了呢?其實不是的,比如數字 33554432 就可以就可以精確表示成1.0000000 00000000 00000000 * 2^{25},說到這裏結合上面提到的float的內存表示方式,我們可以得出大於 16777216 的數字(不超上限),只要可以表示成小於24個2的n次冪相加,並且每個n之間的差值小於24就能夠精確表示。換句話來說所有大於 16777216 的合理數字,都是[0, 16777215]範圍內的精確數字通過乘以2^n得到的,同理所有小於1的正數,也都是 [0, 16777215] 範圍內的精確數字通過乘以2^n得到的,只不過n取負數就可以了。

16777216 已經被證實是一個邊界,小於這個數的整數都可以精確表示,表示成科學技術法就是1.6777216 * 10^{7},從這裏可以看出一共8位有效數字,由於最高位最大爲1不能保證所有情況,所以最少能保證7位有效數字是準確的,這也就是常說float類型數據的精度。

float小數


從上面的分析我們已經知道,float可表示超過16777216範圍的數字是跳躍的,同時float所能表示的小數也都是跳躍的,這些小數也必須能寫成2的n次冪相加纔可以,比如0.5、0.25、0.125…以及這些數字的和,像5.2這樣的數字使用float類型是沒辦法精確存儲的,5.2的二進制表示爲101.0011001100110011001100110011……最後的0011無限循環下去,但是float最多能存儲23位尾數,那麼計算機存儲的5.2應該是101.001100110011001100110,也就是數字 5.19999980926513671875,計算機使用這個最接近5.2的數來表示5.2。關於小數的精度與剛纔的分析是一致的,當第8位有效數字發生變化時,float可能已經無法察覺到這種變化了。

 

讀取小數存儲的原始值(舉例)

stm32 中小數存儲計算

counter+=0.001;

if(counter==0.01)//該條件永遠不會成立,十進制小數轉換二進制的問題導致,應該轉換爲大於等於或者小於等於

asda=*(vu32*)&counter;可通過該句讀取counter在內存中的存儲的數據;

asda=*(vu32*)&counter;取counter地址,指針類型強制轉換成vu32*,然後*取內容。

0.01爲0x3C23D70A,轉換成2進制

0011 1100 0010 0011 1101 0111 0000 1010

符號位 0 代表正數

指數011 1100 0  爲120  (120-127)=-7,小數點左移動7。(如果是130則130-127=3,表示小數點右移動三位。)

尾數01000111101011100001010  左邊有一個可以理解的二進制點。此數字從浮點數的存儲形式中省略。在尾數的開頭加上1和二進制點可得到以下值:

1.0100 0111 1010 1110 0001 0100 左移7位爲0.0000 0010 1000 1111 0101 1100 0010 1000

http://www.ab126.com/system/7348.html (帶小數的二進制轉換十進制計算器的網址)

轉換爲十進制0.00999999977648258

實際在watch窗口中觀察寫入0.01爲0.00999999978(被四捨五入了)

參考鏈接:https://blog.csdn.net/albertsh/article/details/92385277

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章