當前位置:編程學習大全網 - 編程語言 - 關於定點與浮點

關於定點與浮點

壹.double類型的存儲表示

Java的浮點類型表示完全按照IEEE754標準(Standards of IEEE 754 floating point numbers),有興趣可以上IEEE標準網站(www.ieee.org)查閱.該標準的內容基本上描述了浮點類型的存儲格式(Storage Layout),下面我從中總結幾段,來概括該標準,詳細信息請查閱標準原文.

1.什麽是浮點數.

計算機上表達實數有兩中方法:定點表示(fixed-point)和浮點表示(floating-point).定點表示法就是在現有的數字中間的某個位置固定小數點,整數部分和小數部分的表示和壹個普通整數的表示法沒什麽兩樣.例如,我們的數字長度為4,小數點位於中間,那麽妳可以表示10.28,也可以表示00.01,與這種方法性質類似的定點表示還有使用分數的形式.定點數的固定窗口形式使得他既不能夠表示非常大的數又不能表示非常小的數.並且當除法發生時,大量 的精度丟失.

浮點數采用科學計數法的形式來表示實數.例如123.456可以表示成1.23456×102.相對於定點數的固定窗口(fixed Window)的限制,它采用的是浮動窗口(sliding window),因此可以表示較大精度範圍的壹個實數.

2.存儲布局(Storage Layout)

所謂的存儲布局就是壹個浮點數在內存中如何表示.我們知道浮點數有float和double,前者是4個字節也就是32位,後者是8個字節也就是64位.布局分別為:

符號 指數 小數部分 偏移附加(bias)

單精度 1[31] 8[30-23] 23[22-00] 127

雙精度 1[63] 11[62-52] 52[51-00] 1023

中括號內為位的編號範圍,外面為該部分所占有的位的數量.偏移附加不屬於位表示的內容,是壹個常量,稍後解釋.

符號只有壹位:0-表示正數 1-表示負數

指數部分:用指數部分的值(8位/11位,unsigned)的值 減去 偏移附加 得到該數實際的指數 例如值為200,實際指數為73=200-127.對於雙精度的double來說常量bias=1023

尾數:尾數是什麽?對於壹個科學計數法來講,形式象這樣的 L.M×BE,那麽這個L.M就是所謂的尾數(mantisa).它由壹個起始位和壹個小數部分組成.舉個例子,5可以用科學計數法表示成不同形式:

5*100

0.5*101

50*10-1

那麽我們引進壹個概念,規範化形式(normalized form)和非規範化形式(denormalized form).我們定義規範化形式為小數點位於第壹個不為0的數字後面的表達形式為規範化形式,因此上面的第壹種形式為規範化形式,其他的為非規範化形式,Java中的浮點表示完全按照這個標準,只有兩種形式規範化形式:1.f 和 非規範化形式 0.f .

那麽,對於我們的位布局來說,選用底數為2的話,只有壹個數字是非零的,那就是1.所以我們的隱含起始數字可以不用占用壹個位,因為除了0就只能是1,具體的隱含規則,稍後展示.

3.表示的意義.

對應於上面的表格,每壹個區域對應的值的範圍所表示的浮點數的意義:

符號位s 指數位e 小數位f 所表示的意義v

0 00..00 00..00 +0

0 00..00 00..01

:

11..11 正的非規範實數,計算方法v=0.f × 2(-b+1)

0 00..01

:

11..10 XX..XX 正的規範化實數,計算方法v=1.f × 2(e-b)

0 11..11 00..00 正的無窮大

0 11..11 00..01

:

01..11 無意義的非數字SNAN

0 11..11 10..00

:

11..11 無意義的非數字QNAN

其中b=127(float)/b=1023(double),SNAN表示無效運算結果,QNAN表示不確定的運算結果,都是無意義的.

如果把符號位s改成1,那麽就全部都是負數的含義,其他意義和這相同.

另外我們看到,對於無意義的數字是指數部分為全1時,也就是說這裏有很多種組合都是無意義的非數字,而我們的Java中,判斷壹個數字是否是NAN的做法相當簡單

static public boolean isNaN(double v) {

return (v != v);

}

從這裏可以看出來,虛擬機對於double類型的數據比較時,肯定是先做了指數值的判定,發現不是全1時才作內存的逐位比較.當然這是我得推測,真像不知道是否如此.

再另外,我們''現在十分清楚,double類型所能表示的最小值就是它的值之間的距離,也就是我們所說的精度,數字按這種精度向整數"1階梯式的累加時,正好不能和1完全匹配,換句話說,1不是最小值(精度/距離)的整數倍.因此如果妳設置變量 double d = 0.1;而結果不會是0.1,因為無法表示0.1;

二.怎麽查看double類型的存儲結構?

我們很清楚Java的Double類型提供壹個函數叫做doubleToLongBits函數,這個函數的其實很簡單,我們知道,long類型和double類型都是64位的,他們的內存大小壹樣,這個函數的做法就是把double對應的內存結構復制到同樣大小的long類型變量的內存結構中.返回這個long值.因為Java不支持對double類型做位運算,因此:

1.該函數不可能用Java語言完成,所以他是JNI實現

2.我們利用對long類型的位運算可以把該內存結構打印出來查看.

/**

* 測試

*/

public static void main(String[] args){

myTest t = new myTest();

double d = 0.1d;

long l = Double.doubleToLongBits(d);

System.out.println(t.getLongBits(l));

}

/**

* 得到常整數的bit位表示字符串

* @param a

* @return

*/

public String getLongBits(long a){

//8個字節的字節數組,讀出來

byte[] b = new byte[8];

for(int i=7;i>=0;i--){

b[i] = (byte)(a&0x000000FF);

a = a>>8;

}

return this.byte2hex(b); //調用下面壹個函數

}

/**

* 字節數組轉換成字符串

* @param b

* @return

*/

public static String byte2hex(byte[] b){

StringBuffer sb=new StringBuffer();

String stmp="";

for(int n=0;nstmp=(Integer.toHexString(b[n]&0XFF));

if(stmp.length()==1){

//不足兩位的末尾補零

sb.append("0"+stmp);

} else{

sb.append(stmp);

}

if(n//":"作為分割符

sb.append(":");

}

}

return sb.toString().toUpperCase();

}

0.1打印出來的內存結果是:

3F:B9:99:99:99:99:99:9A

我們恢復壹下和第壹節的表示意義對照表對照壹下:

0 01111111011 1001.....1010

有興趣的話,可以那科學計算器按照第壹節的規則計算壹下它的值,哦,正好就是我們通過System.out.println(d)打印的結果.

  • 上一篇:美國麻省理工知名華人教授陳剛被捕,他究竟犯了什麽罪?
  • 下一篇:十萬火急,轉專業面試問題,路過的,有心的進來看看吧
  • copyright 2024編程學習大全網