如何實作自訂的捨入程序

文章翻譯 文章翻譯
文章編號: 196652 - 檢視此文章適用的產品。
全部展開 | 全部摺疊

在此頁中

結論

Microsoft 產品中有許多不同的捨入演算法。四捨五入演算法範圍從運算圓 Excel 的工作表 Round() 函式中到 Banker 的 Rounding CInt()、 CLng() 和 Round() 函式,在 Visual Basic 中應用程式。本文將告訴您哪些在各種不同的 Visual Basic 捨入函式執行和提供的函式的範例應用程式。在另外本文包括範例實作各種捨入演算法的函式。

其他相關資訊

四捨五入解說

您需要四捨五入當您想要將更大的有效位數的數字轉換成較小的整數位數的數量。最常見的情形是當您需要將浮點數值轉換成整數時。

向下捨入

最簡單的形式的捨入是截斷。之後您想要的精確度的任何數字只是會被忽略。VBA Fix() 函式是截斷的範例。比方說 Fix(3.5) 為 3,而 Fix(-3.5) 為-3。

Int() 函式將四捨五入至最高整數小於值的 [向下。 Int() 和 Fix() 截斷為-正數的情形下,作用方式相同,但負數提供不同的結果: Int(-3.5) 提供-4。

Fix() 函式是對稱四捨五入,因為它影響正數和負數幅度 (絕對值) 會以相同方式的範例。Int() 函式是一個範例的非對稱式四捨五入,因為它以不同方式會影響正數和負數程度。

Excel 具有類似試算表函數: Int()、 Floor() 和 RoundDown()。 Int() 運作方式相同,如同 Int() 在 Visual Basic 應用程式。 Floor() 截斷正數值,但無法運作與負的數字。 RoundDown() 函數運作 VBA Fix() 函式與相同的方式。

Microsoft SQL Server 具有 Round() 函式的 VBA Fix() 函式可以作用。SQL Server 也具有運作的方式一樣 VBA Int() 函式的 Floor() 函數。

向上捨入

SQL Server 與 Excel 都有呼叫永遠會將分數值向上 (多個正) 到下一個值捨入的 Ceiling() 到函式。

Visual Basic 應用程式並沒有對應的往返接函式。不過,負數的數字 Fix() 和 Int() 都可用來捨入向上,不同的方式。

Fix() 四捨五入邁向 0 (向上在絕對的意義,但向下絕對值幅度的角度)。Fix(-3.5) 是-3.5。

Int() 四捨五入遠離 0 (向上方面的絕對值幅度但向下在絕對意義)。Int(-3.5) 是-4。

算術圓

當捨入永遠向下或向上,產生的數字不一定是在接近原始的編號。比方說如果四捨五入 1.9 往下到 1,之處在於比四捨五入到 2 向上很大。很容易就可以看到要從 1.6 至 2.4 的數字四捨五入到 2。

然而,呢是介於 1 到 2 之間等距的 1.5 嗎?依慣例,半方式數目被進位的。

您可以實作四捨五入半方式以對稱方式中的數字,-1,或非對稱式的方式-.5 位置進位成 0,捨-.5。

下列函式提供對稱算術四捨五入:
Excel Round() 試算表函數。
SQL Server Round() 函式可以執行對稱算術捨入。

下列函式提供非對稱式算術四捨五入:
Java 數學程式庫的 Round() 方法。

Visual Basic 應用程式並沒有任何函式會執行算術捨入。

banker 的圓

當您將新增圓角的值一起、 永遠四捨五入.5 中相同方向您隨著更多的數字的偏差導致新增在一起。最小化偏差的方法之一是有 banker 的圓。

banker 的捨入輪.5 有時向上和向下有時候。慣例是將四捨五入到最接近的偶數,以便同時 1.5 和 2.5 捨入到 2,和 3.5 以及 4.5 兩者捨入到 4。banker 的捨入是對稱的。

在 Visual Basic 應用程式,下列數值函式會執行 banker 的四捨五入: CByte()、 CInt()、 CLng()、 CCur() 及 Round()。

沒有任何執行 banker 的捨入的 Excel 試算表函數。

隨機圓

甚至 banker 捨入可以 bias 總計。您可以採取額外的步驟來藉由四捨五入.5 向上或向下真正隨機的方式移除偏差。最小如此一來即使資料刻意偏移,偏差可能化。不過,使用隨機四捨五入隨機分散式的資料可能會造成更大的偏差比 banker 的捨入。隨機捨入,可能會導致兩個不同的總數顯示在相同的資料。

沒有 Microsoft 產品實作任何一種隨機捨入的程序。

紅黑相間圓

替代捨入為向上.5 和.5 下之間四捨五入連續呼叫上。

沒有 Microsoft 產品實作替代的捨入程序。

不一致實作 round() 函式

Round() 函式未在不同的 Microsoft 產品間一致的方式實作由於歷史性的原因。

下表會與產品有關實作:
   Product                             Implementation
   ----------------------------------------------------------------------
   Visual Basic for Applications 6.0   Banker's Rounding
   Excel Worksheet                     Symmetric Arithmetic Rounding
   SQL Server                          Either Symmetric Arithmetic Rounding
                                       or Symmetric Round Down (Fix)
                                       depending on arguments

   Java Math library                   Asymmetric Arithmetic Rounding
				

Round() 函式,在 Visual Basic 6.0 和 Visual Basic 6.0 應用程式在執行 banker 的捨入。它有一個可選的第二個引數指定的小數位數四捨五入到數:
   Debug.Print Round(2.45, 1) returns 2.4.
				

範例資料

下表顯示一些範例資料和各種捨入方法的效果在數字和產生的總計。
   Number/Int./Fix/Ceiling/Asym. Arith./Sym. Arith./Banker's/Random/Alt.
   ---------------------------------------------------------------------
   -2.6   -3   -2  -2      -3          -3           -3       -3     -3
   -2.5   -3   -2  -2      -2          -3           -2       -2     -3
   -2.4   -3   -2  -2      -2          -2           -2       -2     -2
   -1.6   -2   -1  -1      -2          -2           -2       -2     -2
   -1.5   -2   -1  -1      -1          -2           -2       -1     -1
   -1.4   -2   -1  -1      -1          -1           -1       -1     -1
   -0.6   -1    0   0      -1          -1           -1       -1     -1
   -0.5   -1    0   0       0          -1            0       -1     -1
   -0.4   -1    0   0       0           0            0        0      0
    0.4    0    0   1       0           0            0        0      0
    0.5    0    0   1       1           1            0        1      1
    0.6    0    0   1       1           1            1        1      1
    1.4    1    1   2       1           1            1        1      1
    1.5    1    1   2       2           2            2        1      1
    1.6    1    1   2       2           2            2        2      2
    2.4    2    2   3       2           2            2        2      2
    2.5    2    2   3       3           3            2        3      3
    2.6    2    2   3       3           3            3        3      3
				

所有的數字的總計:
   Number/Int./Fix/Ceiling/Asym. Arith./Sym. Arith./Banker's/Random/Alt.
   ---------------------------------------------------------------------
   0.0    -9   0   9       3            0           0        1      0
				

所有的負數總計:
   Number/Int./Fix/Ceiling/Asym. Arith./Sym. Arith./Banker's/Random/Alt.
   ---------------------------------------------------------------------
   -13.5  -18  -9  -9      -12          -15         -13      -13    -14
				

所有的正數總計:
   Number/Int./Fix/Ceiling/Asym. Arith./Sym. Arith./Banker's/Random/Alt.
   ---------------------------------------------------------------------
   13.5   9    9   18      15           15          13       14     14
				

下表顯示各種捨入方法之間差異。隨機分散式正數和負數的數字、 Fix()、 對稱的算術四捨五入、 banker 的四捨五入,和替代捨入提供最低差異的實際總數不遠背後的隨機四捨五入。

不過,如果編號可能是所有所有正負 banker 的四捨五入、 替代捨入,及隨機捨入提供最低差異的實際總數。

使用者定義捨入函式的範例

下列函式程式碼範例一節中的程式碼範例提供了捨入的型別所述的每個範例實作。

提供函式是:
   AsymDown      Asymmetrically rounds numbers down - similar to Int().
                 Negative numbers get more negative.

   SymDown       Symmetrically rounds numbers down - similar to Fix().
                 Truncates all numbers toward 0.
                 Same as AsymDown for positive numbers.

   AsymUp        Asymmetrically rounds numbers fractions up.
                 Same as SymDown for negative numbers.
                 Similar to Ceiling.

   SymUp         Symmetrically rounds fractions up - that is, away from 0.
                 Same as AsymUp for positive numbers.
                 Same as AsymDown for negative numbers.

   AsymArith     Asymmetric arithmetic rounding - rounds .5 up always.
                 Similar to Java worksheet Round function.

   SymArith      Symmetric arithmetic rounding - rounds .5 away from 0.
                 Same as AsymArith for positive numbers.
                 Similar to Excel Worksheet Round function.

   BRound        Banker's rounding.
                 Rounds .5 up or down to achieve an even number.
                 Symmetrical by definition.

   RandRound     Random rounding.
                 Rounds .5 up or down in a random fashion.

   AltRound      Alternating rounding.
                 Alternates between rounding .5 up or down.

   ATruncDigits  Same as AsyncTrunc but takes different arguments.
				

所有這些函式會取用兩個引數: 要被四捨五入數和選擇性的因數。如果省略的因數函式會傳回由其中一種以上的方法所建立的整數。如果指定的因數來建立不同的捨入效果係數縮放數。 例如 AsymArith (2.55,10) 會產生 2.6,也就是它將四捨五入至 1/因數 = 1/10 = 0.1。

注意: A 因數為 0 會產生執行階段錯誤: 1/因數 = 1/0。

下表顯示各種因素的影響:
   Expression       Result  Comment
   --------------------------------------------------------------------
   AsymArith(2.5)     3     Rounds up to next integer.
   BRound(2.18, 20)   2.2   Rounds to the nearest 5 cents (1/20 dollar).
   SymDown(25, .1)   20     Rounds down to an even multiple of 10.
				

上述說明例外狀況是 ADownDigits 也就是樣板函式,可讓您指定的一項因素而不是十進位數字數目。
   Expression            Result Comment
   ---------------------------------------------------------------------
   ADownDigits(2.18, 1)    2.1  Rounds down to next multiple of 10 ^ -1.
				

函式程式碼範例


   Function AsymDown(ByVal X As Double, _
            Optional ByVal Factor As Double = 1) As Double
     AsymDown = Int(X * Factor) / Factor
   End Function

   Function SymDown(ByVal X As Double, _
            Optional ByVal Factor As Double = 1) As Double
     SymDown = Fix(X * Factor) / Factor
   '  Alternately:
   '  SymDown = AsymDown(Abs(X), Factor) * Sgn(X)
   End Function

   Function AsymUp(ByVal X As Double, _
            Optional ByVal Factor As Double = 1) As Double
   Dim Temp As Double
     Temp = Int(X * Factor)
     AsymUp = (Temp + IIf(X = Temp, 0, 1)) / Factor
   End Function

   Function SymUp(ByVal X As Double, _
            Optional ByVal Factor As Double = 1) As Double
   Dim Temp As Double
     Temp = Fix(X * Factor)
     SymUp = (Temp + IIf(X = Temp, 0, Sgn(X))) / Factor
   End Function

   Function AsymArith(ByVal X As Double, _
            Optional ByVal Factor As Double = 1) As Double
     AsymArith = Int(X * Factor + 0.5) / Factor
   End Function

   Function SymArith(ByVal X As Double, _
            Optional ByVal Factor As Double = 1) As Double
     SymArith = Fix(X * Factor + 0.5 * Sgn(X)) / Factor
   '  Alternately:
   '  SymArith = Abs(AsymArith(X, Factor)) * Sgn(X)
   End Function

   Function BRound(ByVal X As Double, _
            Optional ByVal Factor As Double = 1) As Double
   '  For smaller numbers:
   '  BRound = CLng(X * Factor) / Factor
   Dim Temp As Double, FixTemp As Double
     Temp = X * Factor
     FixTemp = Fix(Temp + 0.5 * Sgn(X))
     ' Handle rounding of .5 in a special manner
     If Temp - Int(Temp) = 0.5 Then
       If FixTemp / 2 <> Int(FixTemp / 2) Then ' Is Temp odd
         ' Reduce Magnitude by 1 to make even
         FixTemp = FixTemp - Sgn(X)
       End If
     End If
     BRound = FixTemp / Factor
   End Function

   Function RandRound(ByVal X As Double, _
            Optional ByVal Factor As Double = 1) As Double
   ' Should Execute Randomize statement somewhere prior to calling.
   Dim Temp As Double, FixTemp As Double
     Temp = X * Factor
     FixTemp = Fix(Temp + 0.5 * Sgn(X))
     ' Handle rounding of .5 in a special manner.
     If Temp - Int(Temp) = 0.5 Then
       ' Reduce Magnitude by 1 in half the cases.
       FixTemp = FixTemp - Int(Rnd * 2) * Sgn(X)
     End If
     RandRound = FixTemp / Factor
   End Function

   Function AltRound(ByVal X As Double, _
            Optional ByVal Factor As Double = 1) As Double
   Static fReduce As Boolean
   Dim Temp As Double, FixTemp As Double
     Temp = X * Factor
     FixTemp = Fix(Temp + 0.5 * Sgn(X))
     ' Handle rounding of .5 in a special manner.
     If Temp - Int(Temp) = 0.5 Then
       ' Alternate between rounding .5 down (negative) and up (positive).
       If (fReduce And Sgn(X) = 1) Or (Not fReduce And Sgn(X) = -1) Then
       ' Or, replace the previous If statement with the following to
       ' alternate between rounding .5 to reduce magnitude and increase
       ' magnitude.
       ' If fReduce Then
         FixTemp = FixTemp - Sgn(X)
       End If
       fReduce = Not fReduce
     End If
     AltRound = FixTemp / Factor
   End Function

   Function ADownDigits(ByVal X As Double, _
            Optional ByVal Digits As Integer = 0) As Double
     ADownDigits = AsymDown(X, 10 ^ Digits)
   End Function
				

注意: 使用 Excel 的 MRound() 工作表函數,內建的例外-在捨入函式使用引數其中第二個引數指定的一項因素而不是數字數目的 ADownDigits 方式。

捨入此處介紹的實作使用一項因素像 MRound(),這是更有彈性,因為您沒有捨入到 10 的乘冪。 您可以以 ADownDigits 方式撰寫包裝函式。

浮動點限制

此處介紹的捨入實作的所有使用雙精度浮點資料型別可以表示大約 15 個小數位數。

因為並非所有分數的值可以表示完全,您可能會得到非預期的結果,因為顯示值與儲存的值不相符。

比方說數 2.25 可能就儲存在內部為 2.2499999...,它會向下捨入有算術圓,代替向上跟您預期的一樣。而且,多個計算數字放透過預存的二進位值會與理想的十進位值不符合更大的可能性。

如果發生這種情形,您可能要選擇例如是確切 4 個小數位數的貨幣的不同資料類型。

您也可以考慮的製作確切到 28 的十進位數字的資料型別變數和使用 CDec() 將所有項目轉換為 Decimal 資料型別可以是。

四捨五入貨幣值

當您使用已完全 4 的十進位數字,貨幣資料類型您通常想要針對分會捨入到 2 的十進位數字。

下面的 Round2CB 函式是硬式編碼的變化,會執行 banker 的捨入至 2 的十進位數字,但是並不相乘原始的編號。如此可避免可能的溢位條件,如果貨幣量已接近的貨幣資料類型限制。
   Function Round2CB (ByVal X As Currency) As Currency
     Round2CB = CCur(X / 100) * 100
   End Function
				

十進位值捨入

下列是範例的非對稱式算術四捨五入使用 Decimal 資料型別:
   Function AsymArithDec(ByVal X As Variant, _
            Optional ByVal Factor As Variant = 1) As Variant
     If Not IsNumeric(X) Then
       AsymArithDec = X
     Else
       If Not IsNumeric(Factor) Then Factor = 1
       AsymArithDec = Int(CDec(X * Factor) + .5)
     End If
   End Function
				

正在卸除精確度作為捷徑中捨入

在學校的教導,捨入是通常算術捨入使用正數。這種捨入方法,您只需要知道編號為一位數過去您會捨入至。忽略過去的第一個小數位數的數字。亦即精確度卸除作為捨入值的捷徑。

比方說 2.5 和 2.51 圓形最多 3,雖然 2.4 及 2.49 將向下為 2。

當您使用 banker 的捨入 (或其他向上或向下捨入.5 的方法),或捨入使用非對稱式算術捨入的負數,卸除精確度可能會導致不正確的結果,您可能不四捨五入到最接近的數。

比方說有 banker 的圓,2.5 四捨五入向下 2 和 2.51 將四捨五入到最多 3。

使用非對稱式算術捨入,-2.5 將捨入最多-2 時-2.51 四捨五入向下-3。

本文所提出使用者定義函式編號的完整精確度時,考慮執行捨入。

?考

Visual Basic 說明,6.0 版 ; 主題: int,修復函式 ; 四捨五入函式

Microsoft 交易 SQL 說明 ; 主題: 捨入函式 ; 樓層函式 ; 天花板函式

(c) [Microsoft Corporation 1998 年,[保留所有的權限]。藉由所佔的比重 Malcolm Stewart,Microsoft 公司。

屬性

文章編號: 196652 - 上次校閱: 2004年7月15日 - 版次: 3.2
這篇文章中的資訊適用於:
  • Microsoft Visual Basic Control Creation Edition
  • Microsoft Visual Basic 5.0 Learning Edition
  • Microsoft Visual Basic 6.0 Learning Edition
  • Microsoft Visual Basic 5.0 Professional Edition
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic 5.0 Enterprise Edition
  • Microsoft Visual Basic Enterprise Edition for Windows 6.0
  • Microsoft Visual Basic for Applications 5.0
  • Microsoft Visual Basic for Applications 6.0
  • Microsoft SQL Server 6.0 Standard Edition
  • Microsoft SQL Server 6.5 Standard Edition
  • Microsoft SQL Server 7.0 Standard Edition
關鍵字:?
kbmt kbhowto KB196652 KbMtzh
機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:196652
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。

提供意見

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com