HOWTO: 사용자 정의 라운딩 프로시저 구현

기술 자료 번역 기술 자료 번역
기술 자료: 196652 - 이 문서가 적용되는 제품 보기.
이 문서는 이전에 다음 ID로 출판되었음: KR196652
모두 확대 | 모두 축소

이 페이지에서

요약

Microsoft 제품에는 사용할 수 있는 라운딩 알고리즘이 많습니다. 라운딩 알고리즘은 Excel의 워크시트 Round() 함수에 있는 산술 라운딩(Arithmetic Rounding)부터 Visual Basic for Applications의 CInt(), CLng() 및 Round() 함수에 있는 Banker's Rounding에 이르기까지 다양합니다. 본 문서에서는 다양한 Visual Basic for Applications 라운딩 함수의 동작을 설명하고 이들 함수를 사용하는 예제를 제공합니다. 또한 본 문서에는 다양한 라운딩 알고리즘을 구현하는 함수 예제도 제공합니다.

추가 정보

라운딩 설명

정밀도가 더 높은 숫자를 정밀도가 더 낮은 숫자로 변환할 때 라운딩이 필요합니다. 가장 흔한 예로 부동 소수점 숫자를 정수로 변환할 때 라운딩을 사용합니다.

잘라내기

라운딩의 가장 단순한 형태는 잘라내기입니다. 잘라내기에서는 원하는 정밀도 이하의 모든 자리가 무시됩니다. VBA Fix() 함수는 잘라내기의 예입니다. 예를 들어, Fix(3.5)의 결과는 3이고 Fix(-3.5)의 결과는 -3입니다.

Int() 함수는 원래 값보다 작은 가장 큰 정수를 반환합니다. 양수에 대해서는 잘라내기가 적용되어 Int()와 Fix()의 결과가 같지만 음수에 대해서는 결과가 서로 다릅니다. 예를 들어, Int(-3.5)의 결과는 -4입니다.

Fix() 함수는 양수와 음수의 절대값에 동일한 방식으로 영향을 미치는 대칭적 라운딩의 예입니다. Int() 함수는 양수와 음수의 절대값에 서로 다른 영향을 미치는 비대칭 라운딩의 예입니다.

Excel에는 이와 유사한 Int(), Floor(), RoundDown() 등의 스프레드시트 함수가 있습니다. Int()는 Visual Basic for Applications의 Int() 함수와 동일하게 작동합니다. Floor() 함수는 양수에 대해 잘라내기를 수행하며 음수에는 작동하지 않습니다. RoundDown() 함수는 VBA의 Fix() 함수와 동일하게 작동합니다.

Microsoft SQL Server에는 VBA Fix() 함수와 유사하게 사용할 수 있는 Round() 함수가 있습니다. SQL Server에는 VBA Int() 함수와 동일하게 작동하는 Floor() 함수도 있습니다.

반올림

SQL Server와 Excel에는 분수 값을 가장 가까운(양의 방향) 값으로 반올림하는 Ceiling() 함수가 있습니다.

Visual Basic for Applications에는 이와 동일한 반올림 함수가 없습니다. 그러나, 음수에 대해서는 결과는 서로 다르지만 Fix()와 Int()를 반올림에 사용할 수 있습니다.

Fix()는 0에 가까운 쪽으로 라운딩합니다. 즉, 반환된 값은 실제로는 더 크지만 절대값은 더 작아집니다. 예를 들어, Fix(-3.5)의 결과는 -3.5입니다.

Int()는 0에서 먼 쪽으로 라운딩합니다. 즉, 반환된 값은 실제로는 더 작지만 절대값은 더 커집니다. 예를 들어, Int(-3.5)의 결과는 -4입니다.

산술 라운딩(Arithmetic Rounding)

반올림이나 잘라내기를 계속 사용하면 결과 값이 원래 숫자와 가장 근접한 값이 되지만은 않습니다. 예를 들어, 1.9를 잘라내어 1을 만들면 반올림하여 2를 만드는 것보다 원래 값에서 더 멀어집니다. 1.6에서 2.4까지의 숫자는 2로 라운딩해야 한다는 것을 쉽게 알 수 있습니다.

그러나, 1과 2 중 어느 쪽과도 거리가 동일한 1.5의 경우에는 어떻게 해야 할까요? 이와 같은 경우에는 반올림하는 것이 관례입니다.

두 숫자의 가운데 있는 숫자는 -.5를 -1로 잘라내기하는 경우처럼 대칭 방식으로 구현하거나 -.5를 0으로 반올림하는 경우처럼 비대칭 방식으로 구현할 수 있습니다.

아래 함수들은 대칭적 산술 라운딩(Arithmetic Rounding)을 제공합니다.
Excel Round() 스프레드시트 함수.
SQL Server Round() 함수는 대칭적 산술 라운딩(Arithmetic Rounding)을 수행할 수 있습니다.

아래 함수들은 비대칭 산술 라운딩(Arithmetic Rounding)을 제공합니다.
Java Math 라이브러리의 Round() 메서드

Visual Basic for Applications에는 산술 라운딩(Arithmetic Rounding)을 수행하는 함수가 없습니다.

Banker's Rounding

라운딩한 값들을 더할 때 .5를 항상 같은 방향으로 라운딩하면 합계의 편중 오차가 커질 수 있습니다. 편중 오차를 최소화하는 한 가지 방법은 Banker's Rounding을 사용하는 것입니다.

Banker's Rounding에서는 상황에 따라 .5를 반올림하거나 잘라냅니다. 1.5와 2.5는 둘 다 2로 라운딩하고 3.5와 4.5는 둘 다 4로 라운딩하는 방식으로 가장 가까운 짝수로 라운딩하는 것이 규칙입니다. Banker's Rounding은 대칭적입니다.

Visual Basic for Applications에서 Banker's Rounding을 수행하는 숫자 함수는 CByte(), CInt(), CLng(), CCur() 및 Round() 등입니다.

Excel 스프레드시트 함수는 Banker's Rounding을 수행하지 않습니다.

임의 라운딩(Random Rounding)

Banker's Rounding을 수행하더라도 합계에 편중 오차가 발생할 수 있습니다. .5를 임의로 반올림하거나 잘라내는 추가 단계를 수행하여 편중 오차를 없앨 수 있습니다. 이 방법을 사용하면 데이터가 약간 편중될 수는 있지만 편중 오차를 최소화할 수 있습니다. 그러나, 임의로 분포된 데이터에 임의 라운딩(Random Rounding)을 사용하면 Banker's Rounding을 사용할 때보다 오히려 편중 오차가 더 커질 수도 있습니다. 임의 라운딩(Random Rounding)을 사용하면 같은 데이터에 대한 합계가 서로 다를 수도 있습니다.

Microsoft 제품은 어떤 종류의 임의 라운딩(Random Rounding) 프로시저도 구현하지 않습니다.

교대 라운딩(Alternate Rounding)

교대 라운딩(Alternate Rounding)에서는 연속적인 호출에서 한 번은 .5를 반올림하고 다음 번에는 .5를 잘라냅니다.

Microsoft 제품은 교대 라운딩(Alternate Rounding) 프로시저를 구현하지 않습니다.

Round() 함수가 일관성 있게 구현되지 않았다

제품 개발 과정과 관련된 문제로 인해 서로 다른 Microsoft 제품 간에 Round() 함수가 일관성 있게 구현되어 있지 않습니다.

아래 표는 각 제품 및 구현을 요약한 것입니다.
   제품                                구현
   ----------------------------------------------------------------------
   Visual Basic for Applications 6.0   Banker's Rounding
   Excel 워크시트                      대칭적 산술 라운딩(Arithmetic Rounding) 
   SQL Server                          인수에 따라 대칭적 산술 
                                       라운딩(Arithmetic Rounding) 또는 
                                       대칭적 잘라내기(Fix)

   Java Math 라이브러리                비대칭 산술 라운딩(Arithmetic Rounding)

Visual Basic 6.0 및 Visual Basic for Applications 6.0의 Round() 함수는 Banker's Rounding을 구현합니다. 이 함수에는 라운딩할 소수점 자릿수를 지정하는 선택적인 두 번째 인수가 있습니다.
Debug.Print Round(2.45, 1)는 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(), 대칭적 산술 라운딩(Arithmetic Rounding), Banker's Rounding 및 교대 라운딩(Alternate Rounding)을 사용할 때 실제 합계와의 차가 가장 작고 임의 라운딩(Random Rounding)을 사용할 때도 차가 그리 크지 않습니다.

그러나 숫자가 모두 양수이거나 모두 음수인 경우에는 Banker's Rounding, 교대 라운딩(Alternating Rounding) 및 임의 라운딩(Random Rounding)을 사용할 때 실제 합계와의 차가 가장 작습니다.

사용자 정의 라운딩 함수 예제

아래의 "함수 목록" 절에 있는 예제 코드는 앞에서 설명한 각 라운딩 종류에 대한 예제 구현을 제공합니다.

제공되는 함수는 아래와 같습니다.
AsymDown      비대칭적으로 숫자를 잘라냅니다. Int()와 유사합니다. 
              음수는 더욱 작아집니다. 

SymDown       대칭적으로 숫자를 잘라냅니다. Fix()와 유사합니다. 
              모든 숫자를 0의 방향으로 잘라냅니다. 
              양수에 대해서는 AsymDown과 동일합니다. 

AsymUp        분수를 비대칭적으로 반올림합니다. 
              음수에 대해서는 SymDown과 동일합니다. 
              Ceiling과 유사합니다. 

SymUp         분수를 대칭적으로(즉, 0에서 먼 방향으로) 반올림합니다. 
              양수에 대해서는 AsymUp과 동일합니다. 
              음수에 대해서는 AsymDown과 동일합니다. 

AsymArith     비대칭 산술 라운딩(Arithmetic Rounding). 항상 .5를 반올림합니다. 
              Java 워크시트 Round 함수와 유사합니다.

SymArith      대칭적 산술 라운딩(Arithmetic Rounding). 0에서 먼 쪽으로 .5를 라운딩합니다. 
              양수에 대해서는 AsymArith와 동일합니다. 
              Excel 워크시트 Round 함수와 유사합니다. 

BRound        Banker's Rounding. 
              .5를 반올림하거나 잘라내어 짝수를 만듭니다. 
              정의에 의해 대칭적입니다. 

RandRound     임의 라운딩(Random Rounding). 
              임의 방식으로 .5를 반올림하거나 잘라냅니다. 

AltRound      교대 라운딩(Alternate Rounding) 
              교대로 .5를 반올림하고 잘라냅니다. 

ATruncDigits  AsyncTrunc와 동일하지만 서로 다른 인수를 받습니다. 

이 함수들은 모두 라운딩할 숫자와 선택적인 factor 등, 두 개의 인수를 받습니다. factor를 지정하지 않으면 함수들은 위 방법 중 하나를 사용하여 나온 정수를 반환합니다. factor를 지정하면 숫자에 factor가 적용되어 다른 라운딩 효과를 냅니다. 예를 들어, AsymArith(2.55, 10)에서는 1/factor = 1/10 = 0.1이 라운딩되어 2.6이 반환됩니다.

참고: factor가 0이면 1/factor = 1/0이 되어 런타임 오류가 발생합니다.

아래 표는 다양한 factor 값의 효과를 보여줍니다.
   식                결과   설명
   --------------------------------------------------------------------
   AsymArith(2.5)     3     가장 가까운 정수로 반올림합니다.
   BRound(2.18, 20)   2.2   가장 가까운 5센트(1/20달러)로 라운딩합니다. 
   SymDown(25, .1)    20    10의 배수인 짝수로 라운딩합니다. 

factor 대신 소수점 자릿수를 지정할 수 있는 템플릿 함수인 ADownDigits에는 이 설명이 적용되지 않습니다.
   식                     결과  설명
   ---------------------------------------------------------------------
   ADownDigits(2.18, 1)    2.1  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() 워크시트 함수를 제외하고, 기본 제공되는 라운딩 함수는 두 번째 인수가 factor 대신 자릿수를 지정하는 ADownDigits와 같은 방법으로 인수를 사용합니다.

여기에 제공된 라운딩 구현은 MRound()와 마찬가지로 factor를 사용합니다. 이 구현에서는 10의 멱으로 라운딩할 필요가 없기 때문에 좀더 융통성이 있습니다. ADownDigits와 같은 방식으로 래퍼(Wrapper) 함수를 작성할 수 있습니다.

부동 소수점 제한 사항

본 문서에 제공된 모든 라운딩 구현은 소수점 이하 약 15자리를 표현할 수 있는 배정밀도(Double) 데이터 형식을 사용합니다.

모든 분수 값을 정확하게 표현할 수 없고 표시 값은 저장된 값과 일치하지 않기 때문에 예상하지 않은 결과를 얻을 수도 있습니다.

예를 들어, 숫자 2.25는 내부적으로 2.2499999...로 저장될 수도 있으며 예상과 달리 반올림되지 않고 잘릴 수도 있습니다. 또한, 숫자가 계산을 많이 거칠수록 저장된 이진 값이 이상적인 소수점 값에서 멀어질 가능성이 커집니다.

이런 경우에는 정확히 소수점 이하 4자리를 갖는 Currency 같은 다른 데이터 형식을 선택할 수도 있습니다.

또한, 데이터 형식을 Variant로 만들고 CDec() 함수를 사용하여 정확하게 소수점 이하 28자리가 될 수 있는 Decimal 데이터 형식으로 변환할 수도 있습니다.

Currency 값 라운딩

정확하게 소수점 이하 4자리를 갖는 Currency 데이터 형식을 사용할 때 센트의 경우 소수점 이하 2자리로 라운딩하는 것이 일반적입니다.

아래의 Round2CB 함수는 소수점 이하 2자리까지 Banker's Rounding을 수행하지만 원래의 숫자를 늘리지 않는 하드 코딩된(Hard-Coded) 변형 함수입니다. 이 함수는 금액이 Currency 데이터 형식의 한계에 도달할 경우 발생할 수 있는 오버플로 조건을 방지합니다.
   Function Round2CB (ByVal X As Currency) As Currency
     Round2CB = CCur(X / 100) * 100
   End Function

Decimal 값 라운딩

아래는 Decimal 데이터 형식을 사용하는 비대칭 산술 라운딩(Arithmetic Rounding)의 예입니다.
   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

정밀도를 떨어뜨리는 빠른 라운딩 방법

학교에서 배웠듯이 일반적으로 라운딩은 양수를 사용하는 산술 라운딩(Arithmetic Rounding)입니다. 이런 종류의 라운딩에서는 라운딩할 자리 바로 다음의 숫자만 알면 됩니다. 소수점 이하 첫 번째 이후 자리의 숫자는 무시합니다. 즉, 값을 쉽게 라운딩하기 위해 정밀도를 떨어뜨리는 것입니다.

예를 들어, 2.5와 2.51은 둘 다 3으로 반올림되는 반면 2.4와 2.49는 둘 다 2로 잘립니다.

Banker's Rounding(또는 .5를 반올림하거나 잘라내는 다른 방법)을 사용할 때 또는 비대칭 라운딩(Arithmetic Rounding)을 사용하여 음수를 라운딩할 때 정밀도를 낮추면 가장 근접한 숫자로 라운딩되지 않고 잘못된 결과를 얻을 수도 있습니다.

예를 들어, Banker's Rounding에서 2.5는 2로 잘리고 2.51은 3으로 반올림됩니다.

비대칭 산술 라운딩(Arithmetic Rounding)에서 -2.5는 -2로 반올림되는 반면 -2.51은 -3으로 잘립니다.

본 문서에 제공된 사용자 정의 함수는 라운딩을 수행할 때 숫자의 전체 정밀도를 고려합니다.

참조

Visual Basic 도움말 버전 6.0; 항목: Int, Fix 함수; Round 함수

Microsoft Transact SQL 도움말; 항목: Round 함수; Floor 함수; Ceiling 함수

(c) Microsoft Corporation 1998, All Rights Reserved. Contributions by Malcolm Stewart, Microsoft Corporation.

속성

기술 자료: 196652 - 마지막 검토: 2004년 1월 23일 금요일 - 수정: 3.0
본 문서의 정보는 다음의 제품에 적용됩니다.
  • Microsoft Office 97 Professional Edition
  • Microsoft SQL Server 6.0 Standard Edition
  • Microsoft SQL Server 6.5 Standard Edition
  • Microsoft SQL Server 7.0 Standard Edition
키워드:?
kbvbp500 kbvbp600 kbgrpvbdb kbexcel kbvba KB196652

피드백 보내기

 

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