您好,登錄后才能下訂單哦!
如何分析Java float和double精度范圍大小,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
要想理解float和double的取值范圍和計算精度,必須先了解小數是如何在計算機中存儲的:
舉個例子:78.375,是一個正小數。要在計算機中存儲這個數,需要把它表示為浮點數的格式,先執行二進制轉換:
78.375的整數部分:
小數部分:
所以,78.375的二進制形式就是1001110.011
然后,使用二進制科學記數法,有
注意,轉換后用二進制科學記數法表示的這個數,有底有指數有小數部分,這個就叫做浮點數
在計算機中,保存這個數使用的是浮點表示法,分為三大部分:
第一部分用來存儲符號位(sign),用來區分正負數,這里是0,表示正數
第二部分用來存儲指數(exponent),這里的指數是十進制的6
第三部分用來存儲小數(fraction),這里的小數部分是001110011
需要注意的是,指數也有正負之分,后面再講。
如下圖所示(圖片來自維基百科):
比如float類型是32位,是單精度浮點表示法:
符號位(sign)占用1位,用來表示正負數,
指數位(exponent)占用8位,用來表示指數,
小數位(fraction)占用23位,用來表示小數,不足位數補0。
而double類型是64位,是雙精度浮點表示法:
符號位占用1位,指數位占用11位,小數位占用52位。
到這里其實已經可以隱隱看出:
指數位決定了大小范圍,因為指數位能表示的數越大則能表示的數越大嘛!
而小數位決定了計算精度,因為小數位能表示的數越大,則能計算的精度越大咯!
可能還不夠明白,舉例子吧:
float的小數位只有23位,即二進制的23位,能表示的最大的十進制數為2的23次方,即8388608,即十進制的7位,嚴格點,精度只能百分百保證十進制的6位運算。
double的小數位有52位,對應十進制最大值為4 503 599 627 370 496,這個數有16位,所以計算精度只能百分百保證十進制的15位運算。
需要注意的是指數可能是負數,也有可能是正數,即指數是有符號整數,而有符號整數的計算是比無符號整數麻煩的。所以為了減少不必要的麻煩,在實際存儲指數的時候,需要把指數轉換成無符號整數。那么怎么轉換呢?
注意到float的指數部分是8位,則指數的取值范圍是 -126到+127,為了消除負數帶來的實際計算上的影響(比如比較大小,加減法等),可以在實際存儲的時候,給指數做一個簡單的映射,加上一個偏移量,比如float的指數偏移量為127,這樣就不會有負數出現了。
比如
指數如果是6,則實際存儲的是6+127=133,即把133轉換為二進制之后再存儲。
指數如果是-3,則實際存儲的是-3+127=124,即把124轉換為二進制之后再存儲。
當我們需要計算實際代表的十進制數的時候,再把指數減去偏移量即可。
對應的double類型,存儲的時候指數偏移量是1023。
所以用float類型來保存十進制小數78.375的話,需要先轉換成浮點數,得到符號位和指數和小數部分。
這個例子前面已經分析過,所以:
符號位是0,
指數位是6+127=133,二進制表示為10 000 101,
小數部分是001110011,不足部分請自動補0。
連起來用float表示,加粗部分是指數位,最左邊是符號位0,代表正數:
0 10000101 001110011 00000 00000 0000
如果用double來保存。。。自己計算吧,太多0了。
Java中float占4個字節,32bit。計算范圍公式為 ((-1)^S)* (2^(E-127))*(1.M) ,其中S占一位是符號位,E所占8bit是指數位,M占23位是尾數位。
這里一開始(1.M)部分一開始我一直沒想明白為什么前面是1,突然有一天腦子開竅了,科學計數法表示的時候小數點前面就必須是1,所以規格化的時候小數點前面是1。
E占8位,所以大小是0-255,但是為了表示小數,指數部分需要可以是小數,對半一分,所以最后是E-127,也就是說指數部分為-127-128。
尾數部分沒什么好說的,范圍就是1-1.11……(23位全是1)
注意 :尾數這里1.1111實際上是 十進制的1 + 二進制的0.1111, 什么意思呢, 舉例說明會清楚一點:
1.1 ----> 1+1/2 = 1.5 = 2-1/2
1.11 -----> 1+1/2 +1/4 = 1.75 = 2-1/4
總結一下上面的,按道理最大值應該是(2^128)*(2-2^(-23))=2^129-2^105=6.81*10^38,但是一般書上說的都是3.40*10^38,那么問題又來了,為什么會大了2倍?
排除掉所有出書的人抄來抄去的行為導致所有的書都錯了這個因素,那么剩下的只能是上面某個地方出了問題。首先,回到上面那個我加粗的規格化上去(我個人覺得完全可以用一般情況來代替這個詞),仔細想想,假如所有的數都是上面那種規格化表示的時候:
第一:得到的數永遠是(1.M)乘以一個數,指數部分是不會為0的,那么0怎么表示?
第二:無窮大和無窮小,還有NAN(not a number)又是怎么用這32bit表示出來的?我曾經想過的一個解釋是,計算機里沒有那個數就表示NAN嘛。。。以前還真覺得這個好有道理來著。但是計算機這個東西你只能當做一個工具,也就是說它不能無中生有,它只能處理我們給它的東西,所有無窮大無窮小還有NAN在計算機里肯定有一種表示方式。
所以,一定還有非規格化的表示,也就是所謂的特殊情況。
第一:當E是8個0的時候,此時就不是(1.M)而是(0.M)了,這個時候就可以表示出0了,當然還可以表示那些非常接近0的數。
第二:當E是8個1的時候,如果小數域全是0,表示的是無窮,其余的表示NAN。
由上可知,指數部分為(0-127)和(255-127)的時候表示的是兩種特殊情況,所以E的范圍應該是【-126,127】。最后,得出的結論是規格化的浮點數的表示范圍是 正負(2^127)*(2-2^(-23))=2^128-2^104=3.40*10^38
關于如何分析Java float和double精度范圍大小問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。