Round Function
The Round function truncates a numeric value to the configured decimal digits. Rounding involves converting a numeric value with a specified precision to the nearest value with less precision. In a midpoint value, the value after the least significant digit in the result is exactly half way between two numbers.
3.47500 is a midpoint value if it is to be rounded two decimal places, and 7.500 is a midpoint value if it is to be rounded to an integer
In these cases, the nearest value can't be easily identified without a rounding convention. The Round method supports two rounding conventions for handling midpoint values:
Rounding Away from Zero: Midpoint values are rounded to the next number away from zero.
EXAMPLE: Rounding Away from Zero
3.75 rounds to 3.8, 3.85 rounds to 3.9, -3.75 rounds to -3.8, and -3.85 rounds to -3.9
This form of rounding is represented by the MidpointRounding.AwayFromZero enumeration member.
Rounding away from zero is the most widely known form of rounding.
Round to Nearest, or Banker's Rounding: Midpoint values are rounded to the nearest even number.
EXAMPLE: Round to Nearest, or Banker's Rounding
Both 3.75 and 3.85 round to 3.8, and both -3.75 and -3.85 round to -3.8
This form of rounding is represented by the MidpointRounding.ToEven enumeration member.
Rounding to Nearest is the standard form of rounding used in financial and statistical operations. It conforms to IEEE Standard 754, section 4. When used in multiple rounding operations, it reduces the rounding error that is caused by consistently rounding midpoint values in a single direction. In some cases, this rounding error can be significant.
Rounding and Precision
To determine whether a rounding operation involves a midpoint value, the Round method multiplies the original value to be rounded by 10n, where n is the desired number of fractional digits in the return value, and then determines whether the remaining fractional portion of the value is greater than or equal to .5. This is a slight variation on a test for equality, and as discussed in the "Testing for Equality" section of the Double reference topic, tests for equality with floating-point values are problematic because of the floating-point format's issues with binary representation and precision. This means that any fractional portion of a number that is slightly less than .5 (because of a loss of precision) will not be rounded upward.
You can use the method to round a value to the first integer or to the second decimal digit. The ROUND function works in this way:
Round (Double, Int32) - Round (3.4, 0)
Double = (Number to be rounded) 3.4
Int32 = (Number of decimal digits) 0
Result = 3.0
Round (Double, Int32) - Round (3.648, 2)
Double = (Number to be rounded) 3.648
Int32 = (Number of decimal digits) 2
Result = 3.65
The following example illustrates the problem. It repeatedly adds .1 to 11.0 and rounds the result to the nearest integer. Regardless of the rounding convention, 11.5 should round to 12. However, as the output from the example shows, it does not.
| Value | Full Precision | ToEven | AwayFromZero |
|---|---|---|---|
| 11.1 | 11.1 | 11 | 11 |
| 11.2 | 11.2 | 11 | 11 |
| 11.3 | 11.299999999999999 | 11 | 11 |
| 11.4 | 11.399999999999999 | 11 | 11 |
| 11.5 | 11.499999999999998 | 11 | 11 |
| 11.6 | 11.599999999999998 | 12 | 12 |
| 11.5 | 11.5 | 12 | 12 |
This example uses the "R" standard numeric format string to display the floating-point value's full precision and shows that the value to be rounded has lost precision during repeated additions. Its actual value is 11.499999999999998. The value is not rounded to the next highest integer because .499999999999998 is less than .5.
Problems of precision in rounding midpoint values are most likely to arise in the following conditions:
- When a fractional value cannot be expressed precisely in the floating-point type's binary format.
- When the value to be rounded is calculated from one or more floating-point operations.
- When the value to be rounded is a Single rather than a Double or Decimal.
In Cases where the lack of precision in rounding operations is problematic, you can do the following:
- If the rounding operation calls an overload that rounds a Double value, you can change the Double to a Decimal value and call an overload that rounds a Decimal value instead. Although the Decimal data type also has problems of representation and loss of precision, these issues are far less common.
- Define a custom rounding algorithm that performs a "nearly equal" test to determine whether the value to be rounded is acceptably close to a midpoint value. The following example defines a RoundApproximate method that examines whether a fractional value is sufficiently near to a midpoint value to be subject to midpoint rounding. As the output from the example shows, it corrects the rounding problem shown in the previous example.
See Configuring - Round Function for details on how to configure this function.