JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Java 新手區  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友    訂閱主題
reply to postflat modego to previous topicgo to next topic
本主題所含的標籤
作者 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? [Re:worookie]
item1394

松隆子



發文: 81
積分: 4
於 2003-10-14 18:02 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
假設你現在正在設計某些 Java 程式,其中牽涉到浮點數的計算,假定你的程式碼中設有變數其值等於0.1,然後連加它自己兩次,範例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Fp1
{
     public static void main(String argv[])
     {
          double val1 = 0.1;
          double val2 = 0.3;
 
          double d = val1 + val1 + val1;
 
          if (d != val2)
          {
               System.ou.println(" d != val2 ");
          }      
          
          System.out.println
          ( "d - val2 =" + (d - val2) );
     }
}

每個人都知道
0.1 + 0.1 + 0.1 = 0.3
至少在數學上是這樣的, 但是當你執行 Fp1 這個程式時,你會發現結果不再是如此,程式執行結果如下:
1
2
         d != val2
         d - val2 = 5.551115123125783E-17

這個結果似乎是說 0.1 + 0.1 + 0.1 其結果跟 0.3 差了大約 5.55e-17

問題出在哪呢?這個問題就是 IEEE754 浮點數運算( IEEE 754 floating-point arithmetic)
,這可在 Java 語言中找到, Java 語言並不使用小數點(或十進位)去表現數字,相反的它採用(二進位)分數和指數,要實際了解以上所說是什麼意思,我們考慮試著寫出數個小數以分數表示的式子
0.5 = 1/2
0.75 = 1/2 + 1/4
0.875 = 1/2 + 1/4 + 1/8
0.1 = 1/16 + 1/32 + 1/256 + 1/512 +1/4096 + 1/8192 + ...
最後這一個級數是無窮止境的繼續下去,這意味著 0.1 不能準確的以浮點數型態表現,這無窮級數必須在某一點切斷, 做一些捨去或進位的動作...等等, 目的要以64位元double型態表現,而這將會導致一些誤差
底下是另外一個例子,以浮點數運算的結果將會與你預期以數學規則作運算的結果有所不同
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Fp2
{
     public static void main(String argv[])
     {
       double val1 = 12345.0;
       double val2 = 1e-16;
         
       if(val1 + val2 == val1)
       {
            System.out.println(" val1 + val2 == val1 ");
       }
     }
}

其結果如下:
1
val1 + val2 ==val1

就數學觀點來看, 如果
a > 0 && b > 0

a + b !=a
但是程式跑出來的結果明顯違反這個規則, 這問題出在浮點數型態變數的精確度,所謂的精確度就是用多少位元( bits )去表現這一個值(二進位的分數),而且其範圍與可用浮點數型態表示的值之範圍有所不同,對於Java double 形態的變數來說,有53bits的精確度,或是大約16位數(十進位),上述的例子包含一個精確度大約20位數,因為上式可改寫成
1.2345e+4 + 1e-16
因為double形態變數的精確度不足以表示這個加法的結果,所以 1e-16實際上被省略掉了
下面另一個例子是描述數學規則是如何被破壞的
1
2
3
4
5
6
7
8
9
10
11
public class Fp3
{
     public static void main(String argv[])
     {
          double d1 = 1.6e308;
          double d2 = d1 * 2.0 / 2.0;
 
          System.out.println( d1 );
          System.out.println( d2 );
     }
}

如果d1乘以2.0且除以2.0其結果應為d1,是吧?很不幸的結果並不是如此,其結果實際如下:
1
2
1.6e308
                Infinity

首先d1乘以2.0其值已超過精確度所能提供的位數,而之後再除以2.0已於事無補, double 型態變數其最大值大約為1.8e308, 1.6e308乘以2.0, 其結果等於3.2e308, 顯示出來的結果及為正無限大(positive infinity)

再來看看其他例子,如果你曾做過數學整數運算就會知道任何數除以零均是無意義的( ArithmeticException ),但是同樣的運算若以浮點數做處理又會如何呢?例子如下:
1
2
3
4
5
6
7
8
9
public class Fp4
{
     public static void main(String argv[])
     {
         System.out.println( 1.0/0.0 );
         System.out.println( 1.0/-0.0 );
         System.out.println( 0.0/0.0 );
     }
}

其結果為
1
2
3
         Infinity
        -Infinity
         NaN

這個程式對於以浮點數除以零這個式子沒有丟出例外(Exception),當一個正數或負數除以零時,其結果均為無限大

上面的例子表示出事實上不只有一個零,其實有正負零之分,當決定除式結果是正無限大或負無限大時,零之正負將會被考慮進計算之中
那麼第三個式子又如何呢? 0.0/0.0 其結果為 NaN(not a number)
正負零與NaN有一些奇怪的特性,來看看以下的例子來了解這句話
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Fp5
{
     public static void main(String argv[])
     {
          double d1 = -0.0;
          double d2 = +0.0;
          if(d1<d2)
          { System.out.println( -0.0 < +0.0); }
          
          double d3 = 0.0/0.0;
          if(d3 == d3)
          { System.out.println( " d3 == d3 " ); } 
     }
}

如果你執行 Fp5 這個程式,你將會看不到任何東西,如同你所看到之前的例子,零的正負號會影響計算, 就像 1.0/ -0.0 == -infinity 和 1.0/ +0.0 == infinity 但這並不能就因此說 -0.0 < +0.0,上述的例子說明了這件事( d1不小於d2,所以並不顯示任何東西), 不管就你的觀點 -0.0是否跑得比 +0.0還"前面"
Fp5 也說出了一個重點那就是 NaN 是不受控制的( unordered ), 所以d3並不等於它自己,這是一個方法(way)你可以寫出一個方法(method)去分辨一個數是否是NaN(not a number),如果一個數不等於它自己那麼它就是NaN,這種方法(method)事實上已經存在,你可以看看 Float.isNan和Double.isNaN這兩個方法

我們來看看最後這個例子,我們用這個例子來試著描述一個規則關於之前所討論到奇特的浮點數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public calss Fp6
{
      static double[] list = 
       {
            Double.NEGATIVE_INFINITY,
            -0.0,
            +0.0,
            Double.MIN_VALUE,
            Double.MAX_VALUE,
            Double.POSITIVE_INFINITY
        };
    
        public static void main(String argv[]) 
        {
            for (int i = 0; i < list.length; i++) 
            {
                System.out.println(list[i]);
            }
        }
}

其結果為
1
2
3
4
5
6
            -Infinity
            -0.0
             0.0
             4.9E-324
             1.7976931348623157E308
             Infinity

注意 Double.MAX_VALUE 和 Double.POSITIVE_INFINITY 是不同的值
這篇文章提出有關浮點數運算的一些特色.
在使用浮點數時必須要小心,
因為它所產生出來的結果將會與你所預期的不同,
如果你僅僅是應用數學法則去使用它的話

未完...


item1394 edited on 2004-06-07 08:53
reply to postreply to post
話題樹型展開
人氣 標題 作者 字數 發文時間
24961 [精華] [FAQ] 為何 1.0 - 0.8 不是 0.2? worookie 59 2003-10-14 01:40
23297 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? ymshin 25 2003-10-14 01:56
23384 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? qop 170 2003-10-14 02:34
23203 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? ymshin 244 2003-10-14 02:40
23181 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? qop 116 2003-10-14 10:01
24130 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? item1394 466 2003-10-14 14:45
23194 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? metavige 149 2003-10-14 17:03
23082 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? item1394 65 2003-10-14 17:40
25178 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? item1394 4558 2003-10-14 18:02
22912 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? worookie 17 2003-10-15 01:19
22869 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? worookie 76 2003-10-15 01:26
23183 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? T55555 193 2003-10-15 00:14
23112 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? koji 1103 2003-10-15 02:15
23424 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? jini 354 2003-10-15 02:19
22938 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? item1394 79 2003-12-26 10:01
12362 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? 小a 366 2011-01-18 23:19
12354 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? 小a 401 2011-01-18 23:24
12537 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? 小a 159 2011-01-18 23:27
8271 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? Alumisun 147 2013-05-05 23:03
7458 Re:[FAQ] 為何 1.0 - 0.8 不是 0.2? coolmaning 180 2013-10-23 11:44
» JWorld@TW »  Java 新手區

reply to postflat modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8