隨筆 - 17  文章 - 49  trackbacks - 0
          <2006年9月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          1234567

          常用鏈接

          留言簿(1)

          隨筆分類(17)

          隨筆檔案(17)

          相冊(cè)

          最新隨筆

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          ?

          2006 913 星期三

          不要用floatdouble來(lái)進(jìn)行精確的小數(shù)計(jì)算

          ?

          什么?難道它們不就是為了小數(shù)計(jì)算而生的么?在我看到 effective java item31 的時(shí)候,發(fā)出了這個(gè)孤陋寡聞的疑問(wèn)。

          ?

          知其然:

          為什么說(shuō)不能用 float double 來(lái)進(jìn)行精確小數(shù)計(jì)算呢?

          試試執(zhí)行這樣的語(yǔ)句:

          System.out.println( 1.03 ? - ?. 42 ); // 答案是0.6100000000000001?!

          System.out.println(
          1.00 ? - ? 9 * . 10 ); // 答案是0.09999999999999995?!

          你會(huì)發(fā)現(xiàn)結(jié)果和你的小學(xué)數(shù)學(xué)課程有沖突。

          ?

          知其所以然

          之所以出現(xiàn)這樣的奇怪答案,是因?yàn)?/span> float double 不能精確的表達(dá) 0.1 ,或者任何 10 的負(fù) n 次方。他們是設(shè)計(jì)來(lái)進(jìn)行科學(xué)和工程上的計(jì)算,提供精確的近似值的。它們?cè)谏婕敖鹑诜矫娴挠?jì)算則是不在行的。因?yàn)榻鹑诜矫嬉蠼^對(duì)的精確。

          ?

          解決方法

          BigDecimal int 或者 long

          ?

          ?

          BigDecimal?bd? = ? new ?BigDecimal( " 1.00 " );

          ?

          ?

          把所有牽涉到的小數(shù)都以這種方式轉(zhuǎn)變?yōu)?/span> BigDecimal 對(duì)象,然后用它提供的方法進(jìn)行計(jì)算。

          你就得到了精確的計(jì)算結(jié)果,隨之而來(lái)有兩個(gè)小缺點(diǎn),一個(gè)。。。很顯然,就是比直接用原始類型要麻煩,也不能用 +,-,*,/ 這些直觀的符號(hào)了;第二個(gè)就是速度會(huì)慢一點(diǎn),如果不是用于大量的循環(huán)之中,則不是那么要緊。不過(guò),你也同時(shí)得到了一個(gè)好處, BigDecimal 類還帶了豐富的舍入方法,也是不錯(cuò)的。

          如果小數(shù)位本身不長(zhǎng),則可以用 int 或者 long 來(lái)替代,我想你明白這個(gè)方法是什么意思的。在速度必須很快的位置,你又不介意自己看著小數(shù)點(diǎn)位,這個(gè)還是可用的,但如果數(shù)字本身超過(guò)了 18 位,就只能用 BigDecimal 了。

          ?

          Wednesday, September 13, 2006

          Don’t use float and double when exact answers are required

          ?

          What? Aren’t calculating decimal are what they are design for? I made such an ignorant question when I first read effective java-item31.

          ?

          The phenomenon:

          Why we can’t use float and double to calculate decimal when exact results are required?

          Try the following statements:

          ?

          System.out.println( 1.03 ? - ?. 42 ); // the?answer?is?0.6100000000000001?!

          System.out.println(
          1.00 ? - ? 9 * . 10 ); // the?answer?is?0.09999999999999995?!

          ?

          You will find the answers are not agree with what you have learned in primary school.

          ?

          The reason:

          It is all because float and double can not represent exactly 0.1, or any other negative power of ten. They are designed for scientific and engineering calculation which demands accurate approximation. And they are ill-suited for monetary calculations.

          ?

          The solution:

          Use BigDecimal, int or long instead.

          ?

          ?

          BigDecimal?bd? = ? new ?BigDecimal( " 1.00 " );

          ?

          ?

          Transfer all decimal numbers involved in the calcution into BigDecimal objects as above, and then use them to calcute for a exact result, following with two disadvantages, the first, obviously, less convenient than using primitive types, all notations like +,-,*,/ can not be applied neither; the second, it will be slower, which can be ignored if it was not used in a heavily repeated loop. But you also get one merit which comes from the fact that BigDecimal carrys quite a lot of rounding methods.

          If the quantity is not big, you can use int or long instead, you surely understand how to implement the idea. In performance critical section, and you don’t mind keeping track the of the decimal point yourself, this is feasible. But you have not choice if the quantity is over 18 digits, only BigDecimal is available.

          posted on 2006-09-13 19:23 Ye Yiliang 閱讀(8730) 評(píng)論(4)  編輯  收藏 所屬分類: Java

          FeedBack:
          # re: 不要用float和double來(lái)進(jìn)行精確的小數(shù)計(jì)算 2006-09-14 00:21 weide
          從寫Dephi的時(shí)候就發(fā)現(xiàn)了這個(gè)問(wèn)題,尤其在比較大小的時(shí)候讓人相當(dāng)困惑

          然后用C#寫程序的時(shí)候,開(kāi)始全用了Decimal類型,但是這個(gè)計(jì)算過(guò)程也是相當(dāng)?shù)姆爆崳袛?shù)據(jù)在運(yùn)算之間都得轉(zhuǎn)成double,因?yàn)?net提供的數(shù)學(xué)函數(shù)的參數(shù)都是double(或者有不是的,我還沒(méi)找到)

          后來(lái)又花了很大的功夫全變成double了,慘啊-__-|||

          另外就是如何確定有效位數(shù)的問(wèn)題,如果不做取舍,常常會(huì)搞得數(shù)據(jù)超長(zhǎng),當(dāng)參與計(jì)算的數(shù)據(jù)多起來(lái)的時(shí)候,就不知道多少是有效的數(shù)據(jù)了:(

          樓主可有解決辦法?  回復(fù)  更多評(píng)論
            
          # re: 不要用float和double來(lái)進(jìn)行精確的小數(shù)計(jì)算 2006-09-14 08:42 Flyingis
          @weide
          Decimal的構(gòu)造方法應(yīng)該可以直接設(shè)定有效位數(shù)啊。

          關(guān)于這個(gè)問(wèn)題,在《Java Puzzlers》上面也有詳細(xì)的闡述。  回復(fù)  更多評(píng)論
            
          # re: 不要用float和double來(lái)進(jìn)行精確的小數(shù)計(jì)算 2006-09-14 13:06 lgn21st
          《Java Puzzle》上面開(kāi)篇就提到這個(gè)puzzle!  回復(fù)  更多評(píng)論
            
          # re: 不要用float和double來(lái)進(jìn)行精確的小數(shù)計(jì)算 2006-09-14 18:54 冰川
          沒(méi)錯(cuò)!
          金融方面的軟件一般都用BigDecimal.  回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 昭觉县| 霍邱县| 拉萨市| 依安县| 滦平县| 锡林郭勒盟| 唐山市| 岑溪市| 泊头市| 莱阳市| 连云港市| 宣恩县| 安顺市| 鄂州市| 乌兰察布市| 沽源县| 和田县| 莎车县| 米林县| 三明市| 甘南县| 革吉县| 宜兴市| 延安市| 元氏县| 双峰县| 汝城县| 报价| 昌平区| 丹东市| 缙云县| 资阳市| 施甸县| 宣汉县| 大关县| 尼木县| 郸城县| 永济市| 塘沽区| 上林县| 广水市|