文章編號: 125056 - 上次校閱: 2005年2月24日 - 版次: 2.1

資訊: 精確度和浮點計算精確度

系統提示本文適用於您使用的作業系統之外的作業系統。與您不相關的文章內容已停用。

在此頁中

全部展開 | 全部摺疊

結論

有很多情況下哪一種整數位數四捨五入,而浮點計算的精確度可以處理來產生給程式設計人員驚人的結果。有四個應該遵循的一般規則:
  1. 在計算,涉及單一與雙精確度,結果不通常會比單精度任何更精確。如果需要雙精度,一定雙精度中指定所有的搜尋文字,包括常數,計算中。
  2. 絕對不要假設在電腦中,精確地表示一個簡單的數值。最浮點值不能精確地表示為有限的二進位值。例如.1 是.0001100110011...(它重複永遠) 的二進位讓它不能代表電腦使用二進位算術,包括所有個人電腦上的完整精確度。
  3. 絕對不要假設結果是準確的最後一個小數位數。 總是會有 「 真正 」 的答案和可計算以任何浮動點處理單位的有限精確度之間的小差異。
  4. 永遠不會比較兩個浮點數的值,以查看它們是否相等或不相等。這是規則 3 corollary。那里幾乎都將被 「 應該 」 是相等的數字之間的小差異。而是,永遠檢查,看看是否幾乎等於數字。亦即檢查它們之間差異是否非常小或最不顯著。

其他相關資訊

在一般上面所述規則可以套用到所有包括 C、 C + + 和組合語言的語言。下面的範例會示範某些使用 FORTRAN PowerStation 規則。所有的範例使用編譯 FORTRAN PowerStation 32 沒有除了最後一個 C.所撰寫的以外的任何選項

請參閱 FORTRAN 參考手冊隨附的數字常數和內部表示的浮點值的描述的發行項 36068? (http://support.microsoft.com/kb/36068/EN-US/ ) 說明 Microsoft FORTRAN。

範例 1

第一個範例將示範兩件事:

  • FORTRAN 常數是預設的單精度 (C 常數是預設的雙精度)。
  • 包含任何單精度詞彙的計算不會的計算所有的搜尋文字是單精度比更精確的。
之後在初始化與 1.1 (單精度的常數),y 是不正確的為單精度變數。
   x = 1.100000000000000  y = 1.100000023841858
				
的相乘單精度值,由一個精確的雙精度值結果就是為乘以兩個單精度值幾乎為錯誤。這兩個計算已數千次為乘以兩個雙精度值最多錯誤。
   true = 1.320000000000000 (multiplying 2 double precision values)
   y    = 1.320000052452087 (multiplying a double and a single)
   z    = 1.320000081062318 (multiplying 2 single precision values)
				

範例程式碼

C Compile options: none

       real*8 x,y,z
       x = 1.1D0
       y = 1.1
       print *, 'x =',x, 'y =', y
       y = 1.2 * x
       z = 1.2 * 1.1
       print *, x, y, z
       end
				

範例 2

範例 2 使用 quadratic 方程式。它示範甚至雙精度計算並非完美,並計算的結果應該經過測試之前它相依於小錯誤如果可以有極端的結果。平方根函式範例 2 中輸入只是稍微非常負,但仍不正確。如果雙精度計算並沒有輕微錯誤,結果會是:
   Root =   -1.1500000000
				
改,就會產生下列錯誤:
執行階段錯誤 M6201: 數學
-sqrt: 網域時發生錯誤

範例程式碼

C Compile options: none

       real*8 a,b,c,x,y
       a=1.0D0
       b=2.3D0
       c=1.322D0
       x = b**2
       y = 4*a*c
       print *,x,y,x-y
       print "(' Root =',F16.10)",(-b+dsqrt(x-y))/(2*a)
       end
				

範例 3

範例 3 示範因為即使未開啟最佳化發生的最佳化以值可能會暫時保留較高的精確度比預期,及是要測試相等的兩個浮動點值非常周詳。

在這個範例兩個值會有相等和不相等。在第一個 IF Z 值會仍在副處理器的堆疊上,且有相同的精確度為 Y。因此 X 不等於 Y,且第一個訊息列印。在第二個 IF 階段,Z 從記憶體載入,並且因此有相同的整數位數和值,以 X,和第二個訊息也會列印。

範例程式碼

C Compile options: none

       real*8 y
       y=27.1024D0
       x=27.1024
       z=y
       if (x.ne.z) then
         print *,'X does not equal Z'
       end if
       if (x.eq.z) then
         print *,'X equals Z'
       end if
       end
				

範例 4

範例程式碼 4 的第一個部分會計算兩個數字接近到 1.0 之間最小的可能差異。它會將單一位元加入至 1.0 二進位表示。
   x   = 1.00000000000000000  (one bit more than 1.0)
   y   = 1.00000000000000000  (exactly 1.0)
   x-y =  .00000000000000022  (smallest possible difference)
				
有些版本的 FORTRAN 四捨五入數字時顯示它們,讓固有數值 imprecision 不是那麼明顯。這是為什麼 x 和 y 起來相同時顯示。

第二個部分的範例程式碼 4 計算到 10.0 接近 2 個數字之間最小的可能差異。再次,它會藉由將單一位元加入 10.0 二進位表示。請注意靠近 10 的數字之間差異大於接近 1 差異。這示範了一般的原則,越大絕對值的一個數字就越不精確它可以儲存在指定位元數。
   x   = 10.00000000000000000  (one bit more than 10.0)
   y   = 10.00000000000000000  (exactly 10.0)
   x-y =   .00000000000000178
				
二進位表示這些數字也會顯示以顯示它們的差異只在執行不同只有一個位元。
   x = 4024000000000001 Hex
   y = 4024000000000000 Hex
				
範例程式碼 4 最後一個部分顯示的簡單非重複的十進位值通常可以用來表示二進位檔只由重複的分數。在這個案例的 x = 需要重複因數 CCCCCCCC....(Hex) 假數中的 1.05。FORTRAN 中, 最後一個數字"C"接近於"D"為了要維護最高的可能正確性:
   x = 3FF0CCCCCCCCCCCD (Hex representation of 1.05D0)
				
即使之後四捨五入,結果不完全正確。我們可以看到藉由移除第一個數字將最小顯著性數字之後沒有某些錯誤。
   x-1 = .05000000000000004
				

範例程式碼

C Compile options: none

       IMPLICIT real*8 (A-Z)
       integer*4 i(2)
       real*8 x,y
       equivalence (i(1),x)

       x=1.
       y=x
       i(1)=i(1)+1
       print "(1x,'x  =',F20.17,'  y=',f20.17)", x,y
       print "(1x,'x-y=',F20.17)", x-y
       print *

       x=10.
       y=x
       i(1)=i(1)+1
       print "(1x,'x  =',F20.17,'  y=',f20.17)", x,y
       print "(1x,'x-y=',F20.17)", x-y
       print *
       print "(1x,'x  =',Z16,' Hex  y=',Z16,' Hex')", x,y
       print *

       x=1.05D0
       print "(1x,'x  =',F20.17)", x
       print "(1x,'x  =',Z16,' Hex')", x
       x=x-1
       print "(1x,'x-1=',F20.17)", x
       print *

       end
				

範例 5

在 C,浮動常數是預設的雙精度浮點數。使用 「 f 」 來表示為中 89.95f"的浮點值。
   /* Compile options needed: none
   */ 

   #include <stdio.h>

   void main()
   {
      float floatvar;
      double doublevar;

   /* Print double constant. */ 
      printf("89.95 = %f\n", 89.95);      // 89.95 = 89.950000

   /* Printf float constant */ 
      printf("89.95 = %f\n", 89.95F);     // 89.95 = 89.949997

   /*** Use double constant. ***/ 
      floatvar = 89.95;
      doublevar = 89.95;

      printf("89.95 = %f\n", floatvar);   // 89.95 = 89.949997
      printf("89.95 = %lf\n", doublevar); // 89.95 = 89.950000

   /*** Use float constant. ***/ 
      floatvar = 89.95f;
      doublevar = 89.95f;

      printf("89.95 = %f\n", floatvar);   // 89.95 = 89.949997
      printf("89.95 = %lf\n", doublevar); // 89.95 = 89.949997
   }
				

這篇文章中的資訊適用於:
  • Microsoft FORTRAN PowerStation 1.0 Standard Edition
  • Microsoft Fortran PowerStation 1.0a for MS-DOS
  • Microsoft FORTRAN PowerStation 32
  • Microsoft Visual C++ 1.0 Professional Edition
  • Microsoft Visual C++ 1.5 Professional Edition
  • Microsoft Visual C++ 1.51
  • Microsoft Visual C++ 2.0 Professional Edition
  • Microsoft Visual C++ 4.0 Standard Edition
  • Microsoft Visual C++ 5.0 Enterprise Edition
  • Microsoft Visual C++ 6.0 Enterprise Edition
  • Microsoft Visual C++ 5.0 Professional Edition
  • Microsoft Visual C++ 6.0 Professional Edition
  • Microsoft Visual C++, 32-bit Learning Edition 6.0
關鍵字:?
kbmt kbcode kbinfo kblangc kblangfortran KB125056 KbMtzh
機器翻譯機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:125056? (http://support.microsoft.com/kb/125056/en-us/ )
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。