The information in this article applies to:
SUMMARYThere are a number of different rounding algorithms available in Microsoft products. Rounding algorithms range from Arithmetic Rounding in Excel's Worksheet Round() function to Banker's Rounding in the CInt(), CLng(), and Round() functions in Visual Basic for Applications. This article describes what the various Visual Basic for Applications rounding functions do and provides samples of using the functions. In addition, the article includes sample functions that implement various rounding algorithms. MORE INFORMATIONRounding ExplainedYou need to round when you want to convert a number of greater precision into a number of lesser precision. The most common case is when you need to convert a floating-point number into an integer.Rounding DownThe simplest form of rounding is truncation. Any digits after the desired precision are simply ignored. The VBA Fix() function is an example of truncation. For example, Fix(3.5) is 3, and Fix(-3.5) is -3.The Int() function rounds down to the highest integer less than the value. Both Int() and Fix() act the same way with positive numbers - truncating - but give different results for negative numbers: Int(-3.5) gives -4. The Fix() function is an example of symmetric rounding because it affects the magnitude (absolute value) of positive and negative numbers in the same way. The Int() function is an example of asymmetric rounding because it affects the magnitude of positive and negative numbers differently. Excel has similar spreadsheet functions: Int(), Floor(), and RoundDown(). Int() works the same way as Int() does in Visual Basic for Applications. Floor() truncates positive values, but does not work with negative numbers. The RoundDown() function works the same way as the VBA Fix() function. Microsoft SQL Server has a Round() function that can act like the VBA Fix() function. SQL Server also has a Floor() function, which works the same way as VBA Int() function. Rounding UpSQL Server and Excel both have a function called Ceiling(), which always rounds fraction values up (more positive) to the next value.Visual Basic for Applications does not have a corresponding round-up function. However, for negative numbers, both Fix() and Int() can be used to round upward, in different ways. Fix() rounds towards 0 (up in the absolute sense, but down in terms of absolute magnitude). Fix(-3.5) is -3.5. Int() rounds away from 0 (up in terms of absolute magnitude, but down in the absolute sense). Int(-3.5) is -4. Arithmetic RoundingWhen rounding always down or up, the resulting number is not necessarily the closest to the original number. For example, if you round 1.9 down to 1, the difference is a lot larger than if you round it up to 2. It is easy to see that numbers from 1.6 to 2.4 should be rounded to 2.However, what about 1.5, which is equidistant between 1 and 2? By convention, the half-way number is rounded up. You can implement rounding half-way numbers in a symmetric fashion, such that -.5 is rounded down to -1, or in an asymmetric fashion, where -.5 is rounded up to 0. The following functions provide symmetric arithmetic rounding: The Excel Round() spreadsheet function. The following function provide asymmetric arithmetic rounding: The Round() method of the Java Math library. Visual Basic for Applications does not have any function that does arithmetic rounding. Banker's RoundingWhen you add rounded values together, always rounding .5 in the same direction results in a bias that grows with the more numbers you add together. One way to minimize the bias is with banker's rounding.Banker's rounding rounds .5 up sometimes and down sometimes. The convention is to round to the nearest even number, so that both 1.5 and 2.5 round to 2, and 3.5 and 4.5 both round to 4. Banker's rounding is symmetric. In Visual Basic for Applications, the following numeric functions perform banker's rounding: CByte(), CInt(), CLng(), CCur(), and Round(). There are no Excel spreadsheet functions that perform banker's rounding. Random RoundingEven banker's rounding can bias totals. You can take an extra step to remove bias by rounding .5 up or down in a truly random fashion. This way, even if the data is deliberately biased, bias might be minimized. However, using random rounding with randomly distributed data might result in a larger bias than banker's rounding. Random rounding could result in two different totals on the same data.No Microsoft products implement any sort of random rounding procedure. Alternate RoundingAlternate rounding is rounding between .5 up and .5 down on successive calls.No Microsoft products implement an alternate rounding procedure. The Round() Function is Inconsistently ImplementedThe Round() function is not implemented in a consistent fashion among different Microsoft products for historical reasons.The following table relates product to implementation:
The Round() function in Visual Basic 6.0 and Visual Basic for Applications 6.0 performs banker's rounding. It has an optional second argument that specifies the number of decimal digits to round to:
Sample DataThe following table shows some sample data and the effects of various rounding methods on the numbers and totals generated.
Total of all numbers:
Total of all negative numbers:
Total of all positive numbers:
The table shows the difference between the various rounding methods. For randomly distributed positive and negative numbers, Fix(), symmetric arithmetic rounding, banker's rounding, and alternating rounding provide the least difference from actual totals, with random rounding not far behind. However, if the numbers are either all positive or all negative, banker's rounding, alternating rounding, and random rounding provide the least difference from the actual totals. Sample User-Defined Rounding FunctionsThe sample code in the following Function Listing section provides sample implementations for each of the rounding types described.The functions provided are:
All of these functions take two arguments: the number to be rounded and an optional factor. If the factor is omitted, then the functions return an integer created by one of the above methods. If the factor is specified, the number is scaled by the factor to create different rounding effects. For example AsymArith(2.55, 10) produces 2.6, that is, it rounds to 1/factor = 1/10 = 0.1. NOTE: A factor of 0 generates a run-time error: 1/factor = 1/0. The following table shows the effects of various factors:
The exception to the above description is ADownDigits, which is a template function that allows you to specify the number of decimal digits instead of a factor.
Function Listing
NOTE: With the exception of Excel's MRound() worksheet function, the built- in rounding functions take arguments in the manner of ADownDigits, where the second argument specifies the number of digits instead of a factor. The rounding implementations presented here use a factor, like MRound(), which is more flexible because you do not have to round to a power of 10. You can write wrapper functions in the manner of ADownDigits. Floating Point LimitationsAll of the rounding implementations presented here use the double data type, which can represent approximately 15 decimal digits.Since not all fractional values can be expressed exactly, you might get unexpected results because the display value does not match the stored value. For example, the number 2.25 might be stored internally as 2.2499999..., which would round down with arithmetic rounding, instead of up as you might expect. Also, the more calculations a number is put through, the greater possibility that the stored binary value will deviate from the ideal decimal value. If this is the case, you may want to choose a different data type, such as Currency, which is exact to 4 decimal places. You might also consider making the data types Variant and use CDec() to convert everything to the Decimal data type, which can be exact to 28 decimal digits. Rounding Currency ValuesWhen you use the Currency data type, which is exact to 4 decimal digits, you typically want to round to 2 decimal digits for cents.The Round2CB function below is a hard-coded variation that performs banker's rounding to 2 decimal digits, but does not multiply the original number. This avoids a possible overflow condition if the monetary amount is approaching the limits of the Currency data type.
Rounding Decimal ValuesThe following is an example of asymmetric arithmetic rounding using the Decimal data type:
Dropping Precision as a Shortcut in RoundingAs taught in school, rounding is usually arithmetic rounding using positive numbers. With this type of rounding, you only need to know the number to 1 digit past where you are rounding to. You ignore digits past the first decimal place. In other words, precision is dropped as a shortcut to rounding the value.For example, both 2.5 and 2.51 round up to 3, while both 2.4 and 2.49 round down to 2. When you use banker's rounding (or other methods that round .5 either up or down) or when you round negative numbers using asymmetric arithmetic rounding, dropping precision can lead to incorrect results where you might not round to the nearest number. For example, with banker's rounding, 2.5 rounds down to 2 and 2.51 rounds up to 3. With asymmetric arithmetic rounding, -2.5 rounds up to -2 while -2.51 rounds down to -3. The user-defined functions presented in this article take the number's full precision into account when performing rounding. REFERENCES
Visual Basic Help, version 6.0; topic: Int, Fix Functions; Round Function
Keywords : kbExcel kbSQLServ KbVBA kbVBp500 kbVBp600 kbGrpVBDB kbOffice97 |
Last Reviewed: January 5, 2000 © 2000 Microsoft Corporation. All rights reserved. Terms of Use. |