關於float與double結果的誤差

 今日工作遇一字符轉浮點數 沒想用之前用float精度不夠 導致誤差較大 於是參考

http://bbs.51cto.com/thread-542195-1.html  裏面的討論。 引用如下:

float a;
     a=123456.789e5;- s* ~' V9 N; u! H0 x# R
     System.out.printf("%f\n",a);* s- l4 t. Q2 [" E" x" @
8 `* i4 a* S& F4 T! r' p
結果是: ' I7 B$ d* a8 r/ _' a  m# L

    12345678848.000000' u. Z/ l; Z% }& ]* j# }

5 q3 V1 R! M6 T, @' |5 C' e+ b6 o& g
而不是:   12345678900.000000. k. B7 g3 y% t# ~1 o7 }
9 ]1 A( l( E8 m" W* P: P
9 x) [' u; l% o' @2 V

分析:由於float在內存中佔4個字節(32 bit),對於這個數來說會有數據丟失。實型數據是按照指數形式存儲的。系統把一個實型數據分成小數部分和整數部分分別存放。在4個字節中,究竟用多少位來表示小數部分,多少位來表示指數部分,對於不同編譯器可能會有不同。多數是以3 byte (24 bit) 表示小數部分(包括符號),以1 byte (8 bit) 表示指數部分(包括指數的符號)。

看看浮點數是怎樣煉成的,呵呵:4 \, s& c* X* L8 L; Q( `7 M  B

12345678900(十進制)=>
+ c: S1 v- B! w. [3 h$ d! l# u
1011011111110111000001110000110100(34位精確值)

========>
6 Q# p7 w. V, }2 i! z+ x
符號位:0
                           +1279 A4 w- x9 k$ O
指數:33(100001=>00100001 =====> 10100000# g4 V1 ^" l! l3 G" `
                   原碼          階碼(移碼)
                  
尾數:1.01101111111011100000111(取24位)

=>(注意:前面的1在實際存放時爲了多存放一位而隱含,即浮點數的尾數的最高位永遠隱含爲1)- W1 |  V+ Z" M3 L& |+ k
0 10100000 01101111111011100000111(實際放了尾數後面的23位); E! {7 q# L  m( S6 l2 C1 a2 m
     指數           尾數
    
最後結果就是01010000001101111111011100000111

現在再把它還原成整數:9 ?4 S& Q; D0 b1 e, B1 j
(1)取尾數23位:01101111111011100000111
(2)在前面加上隱含的1,變成:101101111111011100000111' Y, h/ A! h* B. I- q0 v  B9 P3 _
(3)取指數8位:10100000
(4)指數減127得:100001(33)6 L  H% k; {0 L9 u- m
(5)尾數向左移動10位(尾數本身23位,33-23=10):10110111111101110000011100000000004 u" _! [: e" s6 b5 {+ z: \
此即123456788485 _, Y4 U& B& Z. ?! o# a4 U- I5 @

8 c! T6 `9 U% q. k
$ @, ?' n' L+ e, l1 d
啓示:在需要精確答案的地方,要避免使用float和double;對於貨幣計算,要使用int、long(把零錢換成分來表示,這時就沒有小數位,然後結果再除以相應的權值.)或BigDecimal。

 

 

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