隨筆 - 9  文章 - 21  trackbacks - 0
          <2008年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          留言簿(1)

          隨筆分類(9)

          隨筆檔案(9)

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          第 2 天的問題

          請考慮下面這段話所描述的問題:

          小明在超市購買了一個價值¥1.10的東西,但是他錢包中只有兩元一張的鈔票。如果他用一張兩元的鈔票支付,那么應該找給他多少零錢呢?

          下面是一個試圖解決上述問題的程序,它會打印出什么呢?

          
          public class Change{
              public static void main(String args[]){
                  System.out.println(2.00 - 1.10);
              }
          }
          
          

          第 2 天問題的解答

          你可能會說,這不是很簡單嘛!輸出0.90。但實際的輸出確實:0.8999999999999999。

          原因

          一、程序如何才能知道你想要打印小數點后兩位小數呢?

          JDK API文檔中關于Double.toString的部分指出:

          Double.toString的返回值,是足以將double類型的值與最靠近它的臨近值區分出來的最短的小數,它在小數點之前和之后都至少有一位。

          因此,看起來,該程序應該打印0.9是合理的。

          二、并不是所有的小數都可以用二進制浮點數來精確表示的。

          問題在于1.1這個數字不能被精確表示成為一個double,因此它被表示成為最接近它的double值。 該程序從2中減去的就是這個值。 遺憾的是,這個計算的結果并不是最接近0.9的double值。 表示結果的double值的最短表示就是你所看到的打印出來的那個可惡的數字。

          第 2 天問題的解決辦法

          方法一

          
          //拙劣的解決方案--仍舊是使用二進制浮點數
          System.out.printf("%.2f%n",2.00 - 1.10);
          

          這條語句打印的是正確的結果,但是這并不表示它就是對底層問題的通用解決方案。它使用的仍舊是二進制浮點數的double運算。 浮點運算在一個范圍很廣的值域上提供了很好的近似,但是它通常不能產生精確的結果。 二進制浮點對于貨幣計算是非常不適合的,因為它不可能將0.1--或者10的其它任何次負冪--精確表示為一個長度有限的二進制小數

          方法二

          System.out.println((200 - 110) + "分");
          

          這是在Java中一種簡單的解決方法。在Java標準庫中,有一個類似的范例Date類,Date類的對于時間的內部表示就是一個以毫秒為單位的long整數。 對于像貨幣這樣的數值,可以用int或long來表示。如果你采納了解決方法,請確保該整數類型大到足夠表示在程序中你將要用到的所有值

          方法三

          
          import java.math.BigDecimal;
          
          public class Change1{
              public static void main(String args[]){
                  System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10")));
              }
          }
          
          

          解決該問題的另一種方式是使用執行精確小數運算的BigDecimal。 這里要告誡你一點: 一定要用BigDecimal(String)構造器,而千萬不要用BigDecimal(double)。 后一個構造器將用它的參數的"精確"值來創建一個實例:new BigDecimal(1.1)將返回一個表示1.100000000000000055511151231257827021181583404541015625 的BigDecimal。

          這個版本并不是十分地完美,因為Java并沒有為BigDecimal提供任何語言上的支持。原因:

          • 使用BigDecimal的計算很有可能比那些使用原始類型的計算要慢一些,對某些大量使用小數計算的程序來說,這可能會成為問題,而對大多數程序來說,這顯得一點也不重要。
          • Java不允許運算符重載。使得代碼不夠直觀。

          總結

          在需要精確答案的地方,要避免使用float和double。

          對于貨幣計算,要使用int、long或BigDecimal。

          對于語言設計者來說,應該考慮對小數運算提供語言支持??梢灾С窒铝蟹绞街械囊环N。

          • 提供對操作符重載的有限支持, 以使得運算符可以被塑造為能夠對數值引用類型起作用, 例如BigDecimal。
          • 提供原始的小數類型,就像 COBOL 與 PL/I 所作的一樣。

          今天的問題

          被除數表示的是一天里的微秒數;而除數表示的是一天里的毫秒數。這個程序會打印出什么呢?

          
          public class LongDivision{
              public static void main(String args[]){ 
                  final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000; 
                  final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000; 
                  System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY); 
              } 
          } 
          
          
          posted on 2008-05-16 22:50 李四飛刀 閱讀(1303) 評論(0)  編輯  收藏 所屬分類: 每日一題
          主站蜘蛛池模板: 县级市| 望谟县| 都安| 水富县| 平果县| 新和县| 乳源| 嘉峪关市| 金沙县| 大埔区| 忻城县| 金乡县| 甘孜| 桓仁| 瑞安市| 兴海县| 涡阳县| 昌平区| 沭阳县| 新巴尔虎左旗| 镇原县| 绥棱县| 巴中市| 阳东县| 琼结县| 宝鸡市| 吉林市| 蒙阴县| 万山特区| 镇赉县| 阜南县| 临泉县| 柳江县| 惠来县| 泌阳县| 德化县| 湘西| 稻城县| 延津县| 原平市| 饶阳县|