析IEEE浮點數表示法

2021-04-08 12:45:35 字數 3347 閱讀 2689

眾所周知,計算機中的所有資料都是以二進位制表示的,浮點數也不例外。然而浮點數的二進位制表示法卻不像定點數那麼簡單了。

先澄清乙個概念,浮點數並不一定等於小數,定點數也並不一定就是整數。所謂浮點數就是小數點在邏輯上是不固定的,而定點數只能表示小數點固定的數值,具用浮點數或定點數表示某哪一種數要看使用者賦予了這個數的意義是什麼。

c++中的浮點數有6種,分別是:

float:單精度,32位

unsigned float:單精度無符號,32位

double:雙精度,64位

unsigned double:雙精度無符號,64位

long double:高雙精度,80位

unsigned long double:高雙精度無符號,80位(嚯,應該是c++中最長的內建型別了吧!)

然而不同的編譯器對它們的支援也略有不同,據我所知,很多編譯器都沒有按照ieee規定的標準80位支援後兩種浮點數的,大多數編譯器將它們視為double,或許還有極個別的編譯器將它們視為128位?!對於128位的long double我也僅是聽說過,沒有求證,哪位高人知道這一細節煩勞告知。

下面我僅以float(帶符號,單精度,32位)型別的浮點數說明c++中的浮點數是如何在記憶體中表示的。先講一下基礎知識,純小數的二進位制表示。(純小數就是沒有整數部分的小數,講給小學沒好好學的人)

純小數要想用二進位制表示,必須先進行規格化,即化為 1.***xx * ( 2 ^ n ) 的形式(「^」代表乘方,2 ^ n表示2的n次方)。對於乙個純小數d,求n的公式如下:

n = 1 + log2(d);// 純小數求得的n必為負數

再用 d / ( 2 ^ n ) 就可以得到規格化後的小數了。接下來就是十進位製到二進位制的轉化問題,為了更好的理解,先來看一下10進製的純小數是怎麼表示的,假設有純小數d,它小數點後的每一位數字按順序形成乙個集合:

那麼d又可以這樣表示:

d = k1 / (10 ^ 1 ) + k2 / (10 ^ 2 ) + k3 / (10 ^ 3 ) + ... + kn / (10 ^ n )

推廣到二進位制中,純小數的表示法即為:

d = b1 / (2 ^ 1 ) + b2 / (2 ^ 2 ) + b3 / (2 ^ 3 ) + ... + bn / (2 ^ n )

現在問題就是怎樣求得b1, b2, b3,……,bn。演算法描述起來比較複雜,還是用數字來說話吧。宣告一下,1 / ( 2 ^ n )這個數比較特殊,我稱之為位階值。

例如0.456,第1位,0.456小於位階值0.5故為0;第2位,0.456大於位階值0.25,該位為1,並將0.45減去0.25得0.206進下一位;第3位,0.206大於位階值0.125,該位為1,並將0.206減去0.125得0.081進下一位;第4位,0.081大於0.0625,為1,並將0.081減去0.0625得0.0185進下一位;第5位0.0185小於0.03125……

最後把計算得到的足夠多的1和0按位順序組合起來,就得到了乙個比較精確的用二進位制表示的純小數了,同時精度問題也就由此產生,許多數都是無法在有限的n內完全精確的表示出來的,我們只能利用更大的n值來更精確的表示這個數,這就是為什麼在許多領域,程式設計師都更喜歡用double而不是float。

float的記憶體結構,我用乙個帶位域的結構體描述如下:

struct myfloat

;符號就不用多說了,1表示負,0表示正

指數是以2為底的,範圍是 -128 到 127,實際資料中的指數是原始指數加上127得到的,如果超過了127,則從-128開始計,其行為和x86架構的cpu處理加減法的溢位是一樣的。比如:127 + 2 = -127;127 - 2 = 127

尾數都省去了第1位的1,所以在還原時要先在第一位加上1。它可能包含整數和純小數兩部分,也可能只包含其中一部分,視數字大小而定。對於帶有整數部分的浮點數,其整數的表示法有兩種,當整數大於十進位制的16777215時使用的是科學計數法,如果小於或等於則直接採用一般的二進位制表示法。科學計數法和小數的表示法是一樣的。

小數部分則是直接使用科學計數法,但形式不是x * ( 10 ^ n ),而是x * ( 2 ^ n )。拆開來看。

0000000000000000000000000000000

符號位指數字尾數字

下面是乙個分析float型別記憶體資料的程式,經測試是完好的,如果發現有問題,請提出來,我好改進。

#include

#include

using namespace std;

int _tmain( int argc, _tchar* argv )

// 將二進位制表示的科學計數法轉換為10進製

dinteger *= pow( 2.0, (double)cexponent );

}else

// 將尾數資料右移小數部分的長度,可得到整數部分。

dinteger = (double)( ulmantissa >> nrightshift );}}

// 以10進製無符號整數方式輸出整數部分

cout << "整數部分:" << setbase( 10 ) << setprecision( 8 );

cout << dinteger << endl;

// 計算出浮點數的小數部分,用無符號長整型表示

double ddecimal = 0;

// 如果指數小於23,則尾數中含小數部分

if ( cexponent < 23 )

else

// 將尾數和mask數進行按位與,可得到小數部分

// 二進位制小數用無符號長整型表示

unsigned long uldecimal = ulmantissa & uldecimalmask;

// dcurbit用來計算和儲存迴圈中對於每一位的位階數

double dcurbit = 0.5;

// 迴圈所有位,計算科學計數法中的小數的十進位制形式

for ( int nbitidx = 1; nbitidx < 24; nbitidx++ )

// 將二進位制表示的科學計數法轉換為10進製

ddecimal *= pow( 2.0, (double)cexponent );

}// 以10進製無符號整數方式輸出小數部分

cout << "小數部分:" << setbase( 10 ) << setprecision( 8 );

cout << ddecimal << endl;

}else

cout << "-----------------------" << endl;

cout << "分析完畢,程式退出。" << endl << endl;

不可改動//

system( "pause" );

//_crtdumpmemoryleaks();

return 0;

不可改動//

}

IEEE的浮點數表示

ieee浮點標準用v 1 s m 2 e 由符號,尾數,階碼表示 32位單精度 單精度二進位制小數,使用32位儲存。1 8 23 位長 s exp fraction 31 30 23 22 0 位編號 從右邊開始為0 偏正值 127 64位雙精度 雙精度 二進位制小數,使用64位儲存。1 11 52...

浮點數表示

之前的一些工作當中碰到了很多有關浮點數的問題,比如浮點數的表達範圍 表達精度 浮點數的儲存方式 浮點數的強制型別轉換等等,因此感覺有必要系統了解一下有關浮點數的問題。浮點數是一種公式化的表達方式,用來近似表示實數,並且可以在表達範圍和表示精度之間進行權衡 因此被稱為浮點數 浮點數通常被表示為 n m...

浮點數表示(IEEE 754標準浮點格式)

浮點數的一般表示形式為 乙個十進位制數 可以寫成 n 10e m 乙個二進位制數 可以寫成 n 2e m其中,m稱為浮點數的尾數,是乙個純小數 e是比例因子的指數,稱為浮點數的指數,是乙個整數。在計算機中表示乙個浮點數時,一是要給出尾數m,用小數形式表示 二是要給出指數e,用整數形式表示,常稱為階碼...