tft每日頭條

 > 圖文

 > 浮點數的階值

浮點數的階值

圖文 更新时间:2024-12-06 00:54:27

寫一篇邏輯嚴密的文章,涉及到的東西太多,實在很困難,所以某些方面就不深究下去,僅做一個知識點的粗淺歸納。

關于浮點數

IEEE754标準規定:

浮點數的構成:1位符号位 N位階碼 M位尾數(原碼表示)

單精度浮點數:1位符号位,8位階碼,23位尾數,共32位,占4個字節

雙精度浮點數:1位符号位,11位階碼,52位尾數,共64位,占8個字節

長雙精度浮點數:1位符号位,15位階碼,64位尾數,共80位,占10個字節

其中,階碼是由原碼加上移碼構成,所謂移碼(exponential bias),值為2^(N-1)-1,如單精度時,移碼為2^7-1=128

NaN表示not a number : 當階碼全為1,尾數不全為0,此時為NaN;這裡又涉及到 quiet NaN和signaling NaN;如果尾數的首位是1,那麼就是quiet NaN;如果尾數的首位是0,其餘尾數有不為0,那麼就是signaling NaN。這是 大多數處理器,包括Intel與AMD的x86系列、Motorola68000系列、AIMPowerPC系列、ARM系列、SunSPARC系列,采取的标準。這個标準被IEEE754采納。

而 PA-RISC與MIPS處理器,采取了首位為'is_signaling'标記位,恰與上述标準相反。

那麼,什麼是quiet NaN和signaling NaN?

意思是:

當一個操作導緻一個安靜的NaN,沒有指示任何異常,直到程序檢查結果并看到一個NaN。也就是說,如果在軟件中實現浮點,計算将繼續進行,而沒有來自浮點單元(FPU)或庫的任何信号。信号NaN将産生一個信号,通常以FPU的例外形式。是否抛出異常取決于FPU的狀态。

以上介紹了浮點數的NaN的定義,下面介紹 Inf和-Inf的定義。

Inf,即正無窮大:當符号位是0,階碼全為1,尾數全是0,此時為正無窮大;

-Inf,即負無窮大:當符号位是1,階碼全為1,尾數全是0,此時為負無窮大;

所以對于64位的雙精度浮點數:

NaN 為:0xFFF8000000000000ULL

Inf為:0x7FF0000000000000ULL

-Inf為:0xFFF0000000000000ULL

下面繼續問:

單精度,雙精度,能表示的最小的小數是多少?我如果知道了每種精度能表示的最小的小數,那麼就會很清楚的去選擇正确的精度類型。

已知:float,單精度浮點數,1位符号位,8位階碼,23位尾數。

既然尾數有23位,那麼能表示的最小的小數對應着23位尾數中,隻有最後一位是1,其餘全是0

即0.0000,0000,0000,0000,0000,001B ,這個二進制對應的小數是2^(-23),即0.000000119D

那麼0.00000012D對應的二進制是多少呢?因為0.000000119D對應的二進制是0.0000,0000,0000,0000,0000,001B,這已經是最小的二進制數,當二進制增加1時,即

0.0000,0000,0000,0000,0000,010B,對應的小數已經是0.000000228D

而,0.00000012D介于0.000000119D和0.000000228D之間,所以0.00000012D的二進制仍舊是0.0000,0000,0000,0000,0000,001B

意思就是:小數點後第8位并不是有效位;那麼小數點後第7位呢?

0.0000,0000,0000,0000,0000,001對應的十進制是0.0000001,

0.0000,0000,0000,0000,0000,010對應的十進制是0.0000002,

所以,float的有效位就是小數點後7位。

以上是從二進制的形式來分析數的有效位;

下面如果面對的是十進制數

比如:0.100000111D,與0.100000112D,這兩個數,如果聲明類型為float,那麼這兩個數是不是相等的?

首先,要對十進制數進行歸一化為1.xxxxx的形式;

如果遇到整數部分不是1的,那麼就會浮動小數點,得到1.00000111和1.00000112

當然小數點浮動了,階碼也改變了。這樣得到的兩個小數,他們的小數部分就是7位有效位。

所以1.00000111就是1.0000011;而1.00000112也是1.0000011,所以說0.100000111,與0.100000112是相等的。

那麼0.00000011122233f 和 0.00000011122234f這兩個數是不是相等的?

從表面看,雖然他們已經在小數點後14位才不一樣,似乎他們應該是相等的。但其實,他們并不相等。因為雖然前面有那麼多的0,但是這是浮點數,它會移動小數點,以達到最精簡的表達這個數,歸一化後為1.1122233f和1.1122234f,此時他們的小數點後是7為數字,不同的位置在第7位,所以計算機可以區分出這兩個數是不同的,所以0.00000011122233f 和 0.00000011122234f這兩個數是不相等的。

float x11=3.00000012f 和 float x22=3.00000010f這兩個數是否相等?

答案是:

不相等。

雖然表明上看,這兩個數的小數部分的前7位都是一樣的,整數部分也一樣,似乎應該是相等的。

x11=3.00000012f的小數部分明顯大于2^(-23),也就是說尾數的第23位是1;x22=3.00000010f的小數部分明顯小于2^(-23),也就是說尾數的第23位是0;

但是,他們的整數部分是3,即二進制11,歸一化後的尾數的第1位被3的二進制的第0位的1占據。

這樣,x11的歸一化之前的尾數的第23位就被劃在了歸一化後的尾數的範圍之外。也就是說x11和x22在歸一化後,他們的尾數都是一樣的了。可是為什麼結果還是不相等呢?

原因在于x11歸一化後,雖然尾數的第23位是0了,但是它的第24位是1,這個1等于了float的

機器ε(machine epsilon)的一半,所以不能舍去,于是向尾數的第23位進1,于是尾數的第23位并不是0,而是1。

至于什麼是 機器ε, 機器ε是指最小的尾數,即尾數的第23位是1時的值。

如果上面的理解是正确的,那麼如果我将x22的值,歸一化之前的小數部分的尾數的第22位設置為1,這樣當将整數部分的3歸一化後,22位上的1變成了23位上的1,這樣x22就與x11一樣了。下面驗證一下,是不是一樣。

當22位上是1時,那麼值就是2^(-22),即0.000000238,于是我程序比較

float x11=3.00000012f 和 float x22=3.00000024f; 這兩個數是不是相等。如果相等,證明我的理解是正确的。

浮點數的階值(初步了解一下浮點數)1

說明我的猜測是正确的。

幾個例子

float x11=3.00000011f 和 float x22=3.00000012f是不相等的;

float x11=3.00000011f 和 float x22=3.00000010f是相等的;

請問,float x11=100.00000022f和float x22=100.00000011f是否相等。

100,劃分為二進制是1100100,歸一化後,它的100100歸入了尾數中,導緻歸一化之前的尾數中的第22,23位都被分離了出去,原來的位17變成了現在的位23,并且原來的位18也是0,即現在的位24是0,所以24位及其後面的都被舍去。即x11和x22是相同的。

也就是說:當一個浮點數,整數部分的值很大時,這會占據小數部分的有效位。

另外,也可以這樣理解:

x11=100.00000022f,歸一化就是1.00 00000022f ;

x22=100.00000011f,歸一化就是1.00 00000011f;

從小數部分數7位,發現以上都是一樣的,所以x11和x22是相等的;

這就是規律。

即:先把數歸一化,得到首尾是1的數,再判斷它的小數部分,7位有效位,同時判斷第8位的值是否超過機器ε的一半。若有,則有進位。否則,舍去。

對于double,雙精度浮點數:

1位符号位,11位階碼,52位尾數,共64位。

那麼它的機器ε就是:2^(-52),即0.000000000000000222

即雙精度浮點數的有效位是小數點後16位。

下面,實際的計算一下,3.1415這個浮點數當類型是雙精度時,在内存中的表示。

3換算為二進制就是11

0.1415換算為二進制就是0010,0100,0011,1001,0101,1000,0001,0000,0110,0010,0100,1101,1101{0...}

所以3.1415的二進制表示就是:

11. 0010,0100,0011,1001,0101,1000,0001,0000,0110,0010,0100,1101,1101{0...}

歸一化為:

1.1 0010,0100,0011,1001,0101,1000,0001,0000,0110,0010,0100,1101,1101{0...}

因為歸一化了,将整數部分的1劃入了尾數,所以此時尾數是:

1 0010,0100,0011,1001,0101,1000,0001,0000,0110,0010,0100,1101,110{10...}

第53位是1,進1,得到:

1.1 0010,0100,0011,1001,0101,1000,0001,0000,0110,0010,0100,1101,111

尾數換算為16進制就是:921CAC083126F

階碼的原碼是1,即2^1,因為這個是雙精度浮點數,可知它的移碼是2^(11-1)-1,即:

十進制數1023,換算為16進制數是3FF,加上階1,得到400

所以3.1415,用雙精度表示就是:

0 {11-1111-1111} {1 0010,0100,0011,1001,0101,1000,0001,0000,0110,0010,0100,1101,111}

從後往前,4bit一組,構成16進制,表示為:

0x400921CAC083126F

下面,用軟件來驗證3.1415的雙精度浮點數,在内存中的值是不是 0x400921CAC083126F

unsigned long long a=0x0;

double b=3.1415;

a=*((unsigned long long *)(&b));

意思是:取得變量b的地址,将這個地址的類型轉換為unsigned long long *,然後取得這個地址的内容,送給a

debug中斷,查看&b的值是0x0012FEA8, 從這個地址開始的8個字節的内存值是:

浮點數的階值(初步了解一下浮點數)2

我的電腦是Intel處理器,數據在内存中是以小尾形式保存的,即數據的高字節保存在内存的高地址處;數據的低字節保存在内存的低地址處。

因此,從地址0x0012FEA8開始的8個字節,組成的數據是0x400921CAC083126F

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved