BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

C# Programming
.NET 2.0+

Rounding Decimal Values in C#

The decimal data type is used to store numbers with a high level of precision. The potentially large number of decimal places held is useful for many mathematical or statistical calculations. However, it is helpful to round values for display purposes.

Rounding Values

C# provides three native numeric data types for holding floating point values. These are the single-precision, double-precision and decimal numbers, which are declared using the "float", "double" and "decimal" keywords respectively. Each of these types holds a different range of possible values with varying levels of precision. The "float" type is the least precise with the smallest range of values and the "decimal" type has the largest range and greatest precision. The selection of the type of value to use for any purpose is a trade-off between the size and accuracy requirements of the numbers being held and the amount of memory used by a declared variable.

In this article we will be working with the decimal data type, not for its size or precision but for the additional functionality provided by this type over the other two options. Specifically, we will be using the four static rounding methods that are only available to decimal values. Of course, you can round single and double-precision numbers too. However, in these cases you must first cast or convert the value to a decimal first or use members of the Math class.

NB: The methods described in this article require the .NET framework version 2.0 or later. Some of the functions are available in .NET 1.1 but there use may be limited.

Truncation

One of the most basic ways to round a decimal is truncation. With truncation, all fractional digits are simply removed from the number leaving only the integer part, though still held in a decimal. This can be easily demonstrated using the following code. Note how the decimal part is removed and the values are rounded downwards to the nearest integer for the first two lines. In the third line, the value remains unchanged, as there is no fractional part. In the last two lines, the negative values are effectively rounded upwards.

decimal result;
result = decimal.Truncate(1.2M);    // result = 1
result = decimal.Truncate(1.9M);    // result = 1
result = decimal.Truncate(1M);      // result = 1
result = decimal.Truncate(-1.2M);   // result = -1
result = decimal.Truncate(-1.9M);   // result = -1

Floor and Ceiling

The static Floor and Ceiling methods perform similar functions to truncation, in that they remove the decimal portion of the number and return an integer. Again the integer is returned within a decimal structure. The key difference between these methods and truncation is that the direction of rounding is fixed for both positive and negative numbers. For the floor function the rounding is always downwards and for ceiling it is always upwards, as can be seen in the results of the sample code below.

decimal result;
result = decimal.Floor(1.2M);       // result = 1
result = decimal.Floor(1.9M);       // result = 1
result = decimal.Floor(1M);         // result = 1
result = decimal.Floor(-1.2M);      // result = -2
result = decimal.Floor(-1.9M);      // result = -2

result = decimal.Ceiling(1.2M);     // result = 2
result = decimal.Ceiling(1.9M);     // result = 2
result = decimal.Ceiling(1M);       // result = 1
result = decimal.Ceiling(-1.2M);    // result = -1
result = decimal.Ceiling(-1.9M);    // result = -1

Controlled Rounding

The three methods described above are useful in many scenarios. However, they are limited to producing integer values and they do not exhibit the normal rules of mathematical rounding. Where this additional functionality is required, the Round method can be used. This gives more control over the rounding for additional flexibility.

In the final sections of this article we will examine the Round method in detail.

Simple Rounding

The simplest manner in which to use the Round method is with a single parameter containing the number to be modified. When used in this way, the return value contains the integer value that is nearest to the passed value.

decimal result;
result = decimal.Round(1.2M);       // result = 1
result = decimal.Round(1.9M);       // result = 2
result = decimal.Round(1M);         // result = 1

When rounding values that are exactly half way between two integers, the method provides what may appear to be a strange result. Try executing the following two statements. You will see that in one case the value is rounded upwards and in the other downwards.

result = decimal.Round(1.5M);       // result = 2
result = decimal.Round(2.5M);       // result = 2

You might expect to see both of the values rounded upwards to return results of two and three respectively. However, by default, this method uses a midpoint rule that specifies that when the value being rounded is exactly half way between two integers, always select the closest even value.

Midpoint Rules

Two midpoint rules are available when rounding values. The first is the default rule that we have seen in the previous sample. This is the "To Even" rule. The alternative is the "Away From Zero" rule, which states that when the rounded value is midway between the two possible outcomes, always choose the value that is furthest from zero. For positive values this means rounding upwards and for negative numbers the result is rounded downwards.

To specify the rule, an addition parameter is added to the method call. This contains a value from the MidpointRounding enumeration.

decimal result;
result = decimal.Round(1.5M, MidpointRounding.ToEven);          // result = 2
result = decimal.Round(2.5M, MidpointRounding.ToEven);          // result = 2
result = decimal.Round(1.5M, MidpointRounding.AwayFromZero);    // result = 2
result = decimal.Round(2.5M, MidpointRounding.AwayFromZero);    // result = 3
result = decimal.Round(-2.5M, MidpointRounding.AwayFromZero);   // result = -3

Rounding to a Specified Number of Decimal Places

All of the examples thus far have considered rounding a value to return an integer. The Round method also permits rounding to a specific number of decimal places. This is achieved by specifying the required number of decimal places as the second parameter to the method, as in the following examples:

decimal result;
result = decimal.Round(1.2345M, 1); // result = 1.2
result = decimal.Round(1.2345M, 2); // result = 1.23
result = decimal.Round(1.2345M, 3); // result = 1.234

The default midpoint rule of "To Even" applies for this rounding, except that the final decimal digit is rounded to the nearest even number.

result = decimal.Round(1.25M, 1);   // result = 1.2
result = decimal.Round(1.35M, 1);   // result = 1.4

You can modify the midpoint rule in use when rounding to a number of decimal places. To do so, simply add the MidpointRounding value as a third parameter:

result = decimal.Round(1.25M, 1, MidpointRounding.AwayFromZero);  // result = 1.3
result = decimal.Round(1.35M, 1, MidpointRounding.AwayFromZero);  // result = 1.4
16 November 2008