今日工作遇一字符转浮点数 没想用之前用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。