float、double的精度、範圍,在內存中的存儲方式

float、double的精度,在內存中的存儲方式

 

一、浮點型變量在內存中的存儲方式

Java的浮點數遵循IEEE 754標準,採用二進制數據的科學計數法來表示浮點數,float遵從的是IEEE R32.24 ,而double 遵從的是R64.53。該標準中表示的浮點數表示分爲規約形式和非規約形式以及特殊情況。

    無論是單精度還是雙精度在存儲中都分爲三個部分:

  1. 符號位(Sign) : 0代表正,1代表爲負
  2. 指數位(Exponent):用於存儲科學計數法中的指數數據,並且採用移位存儲
  3. 尾數部分(Mantissa):尾數部分

根據IEEE 754 標準,對於float單精度,第 31 位(左邊第1位)表示浮點數字的符號;第 30-23位(8位)表示指數(指數加完偏移量,即加偏移量127後的值);第 22-0 位是尾數(尾數是23位);存儲方式如下圖所示:

指數是有符號的,但並不是使用有符號整形(int)的存儲方式,而是使用偏移(Offset)算法,存儲的數據=元數據 + 127,所以【實際指數值 = 指數部分二進制值 - 127】。8位二進制能表示的範圍爲0~255,這樣的話範圍就是(-127~128),另外全0和全1作爲特殊處理,所以指數部分能表示的範圍爲-126~127規約形式。可以參考https://www.zhihu.com/question/21711083

根據IEEE 754 標準,對於double雙精度,第 63 位表示浮點數字的符號;第 62-52 位(11位)表示指數(指數加完偏移量);第 51-0 位是尾數(尾數是52位,尾數位比float多,尾數位越多,精度越高);雙精度的存儲方式爲:

   

指數部分與float單精度存儲方式一樣使用偏移(Offset)算法,存儲的數據=元數據 + 1023,所以【實際指數值 = 指數部分二進制值 - 1023】。11位二進制能表示的範圍爲0~2047,所以指數部分能表示的範圍爲-1022~1023

 

非規約形式表示:

當指數部分全0而且小數部分不全0時表示的是非規格化的浮點數,因爲這裏默認沒有前導1,而是0。

對於float類型,取值位0.f * 2-126,表示範圍位 2-149~(1-2-23) × 2-126 這裏沒有考慮符號。(IEEE 754標準規定:非規約形式的浮點數的指數偏移值比規約形式的浮點數的指數偏移值小1。)

 

其他特殊表示:

1.當指數部分和小數部分全爲0時,表示0值,有+0和-0之分(符號位決定),0x00000000表示正0,0x80000000表示負0.

2.指數部分全1,小數部分全0時,表示無窮大,有正無窮和負無窮,0x7f800000表示正無窮,0xff800000表示負無窮.

3.指數部分全1,小數部分不全0時,表示NaN,分爲QNaN和SNaN,Java中都是NaN.

 

二、二進制的科學計數法

十進制的科學計數法:任何數字都可以表示成a×10n,其中1≤a<10,n表示整數,一般用於表示很大的數字,例如:623500000000可以表示爲6.235×1011。同理,任何二進制都可以表示成a×2n,其中a爲帶小數點的二進制序列,且小數點在第二位,n表示整數,例如:100111101100000000000000可以表示爲1.001111011×223

三、十進制轉換爲二進制

1.整數部分

餘數法:用這個十進制的整數除以 2,會得到一個商值和一個餘數值,再用商除以 2,一直除到商爲 0 爲止,把每次的餘數,逆序連起來,就是要轉的二進制數。整數總能用二進制準確表示。

2.小數部分

小數部分就是用十進制小數乘以2,得出的積,然後把積的整數位取出,再用積的小數部分乘以2,再把積的整數位取出,再用小數部分乘以2,循環操作,直到小數部分爲0,或者遇到無限循環小數轉換爲二進制可能會損失精度),取到你認爲足夠精度的小數爲止,然後把取出的整數位順序連接起來,就是要轉換成的二進制小數。

十進制

二進制

0.5 

0.1 

0.25 

0.01 

0.125 

0.001 

0.0625 

0.0001 

0.03125

0.00001 

0.015625 

0.000001 

0.0078125

0.0000001

0.00390625 

0.00000001 

十進制 0.875 轉換成二進制 0.111,十進制0.3轉換成二進制0.01001100110011…。

四、二進制轉換爲十進制

float與double的二進制表示轉換爲十進制時,先表示爲科學計數法,再分別轉換小數部分和整數部分。

0 01111111 00000000000000000000000的指數部分爲01111111=(27-1)-127 = 0,尾數部分爲00000000000000000000000,(因整數部分總爲1,所以存儲時省略整數部分)該數的科學計數法表示爲1. 00000000000000000000000×20,所以該二進制對應的十進制爲1。

1 10000000 00000000000000000000000的指數部分爲10000000 = 27-127 = 1,尾數部分爲00000000000000000000000,該數的科學計數法表示爲1.00000000000000000000000×21,左移1位變爲10.0000000000000000000000,所以該二進制對應的十進制爲2。

0 01111101 00110011001100110011001的指數部分爲01111101 = 125 – 127 = -2,尾數部分爲00110011001100110011100,該數的科學計數法表示爲1.00110011001100110011100×2-2,右移2位變爲0.0100110011001100110011001,整數部分爲0,小數部分約爲0.3,該數爲0.3。

0 10000000 10010010000111111011011的指數部分爲10000000 = 27 – 127 = 1,尾數部分爲10010010000111111011011,該數的科學計數法表示爲1.10010010000111111011011×21,左移1位變爲11.0010010000111111011011,整數部分爲3,小數部分約爲0. 1415926,該數爲3.1415926。

五、float、double的精度

 數學領域中的精度一般指有效數字,是十進制位數, 而計算機中的精度通常是指二進制位數。

從上述幾個float的二進制表示轉換爲十進制的示例可以看出:

  1. 指數位決定了範圍大小,因爲指數位表示的越大則表示的數值越大。
  2. 尾數位決定了計算精度,因爲尾數位能表示的越大,則計算精度越大。

浮點數的精度決定於尾數部分,而float尾數佔了23個二進制位,加上省略的整數部分的1,共24位決定浮點數的精度。24位二進制表示的最大數字爲224轉化爲十進制數爲 16,777,216(8個十進制位),因此有一種說法是float的十進制精度爲8位,但是由於其並不能表示所有8位十進制數,因此也有種說法是其精度爲7位。【這些說法都不準確,因爲尾數部分包含整數部分和小數部分】準確的說,float可以保證7位十進制有效數字。

float能表示的最大數爲0 11111110 11111111111111111111111,也是Float.MAX_VALUE的值,(224-1)× 2(127-23)約爲3.4028235E38。

float能表示最小正數爲1 00000000 00000000000000000000001(非規約表示),也是Float.MIN_VALUE的值,2-149約爲1.4E-45

 

double位數佔52位,加上省略的整數部分的1,共53位決定浮點數的精度。53位二進制表示的最大數字爲253轉化爲十進制數爲 9,007,199,254,740,992(16個十進制位),但是它不能表示所有16位十進制數,其精度介於15~16位。準確的說,double可以保證15位十進制有效數字。

Double表示的最大數爲1.7976931348623157E308,最小正數爲4.9E-324

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