Click here to Skip to main content
16,020,114 members
Articles / Programming Languages / Visual Basic

Rounding Floating-Point Numbers Up or Down in .NET

Rate me:
Please Sign up or sign in to vote.
4.83/5 (10 votes)
18 May 2011CPOL1 min read 53.5K   20   10
Rounding Floating-Point Numbers Up or Down in .NET

Introduction

Yesterday, I needed to be able not only to round a floating-point number to a certain number of decimal places, but also control the direction the rounding (i.e.: always force it to round down).

Not a problem, I thought. There will be a method on the System.Math class that will let me do just that. How wrong can you be?? My first port of call was the Math.Round() method, but whilst you can specify the number of decimal places with this method, you cannot force it to always round either up or down. Next, I looked at Math.Floor() and Math.Ceiling() methods. These, however, will only round to the nearest integer.

There was nothing else for it, but to roll my own.

The Solution

The code for my solution is as follows:

C#
// C#
public static class EnhancedMath
{
    private delegate double RoundingFunction(double value);

    private enum RoundingDirection { Up, Down }

    public static double RoundUp(double value, int precision)
    {
        return Round(value, precision, RoundingDirection.Up);
    }

    public static double RoundDown(double value, int precision)
    {
        return Round(value, precision, RoundingDirection.Down);
    }

    private static double Round(double value, int precision, 
				RoundingDirection roundingDirection)
    {
        RoundingFunction roundingFunction;
        if (roundingDirection == RoundingDirection.Up)
            roundingFunction = Math.Ceiling;
        else
            roundingFunction = Math.Floor;
        value *= Math.Pow(10, precision);
        value = roundingFunction(value);
        return value * Math.Pow(10, -1 * precision);
    }
}
VB.NET
' Visual Basic
Public Module EnhancedMath

    Private Delegate Function RoundingFunction(ByVal value As Double) As Double

    Private Enum RoundingDirection
        Up
        Down
    End Enum

    Public Function RoundUp(ByVal value As Double, ByVal precision As Integer) As Double
        Return Round(value, precision, RoundingDirection.Up)
    End Function

    Public Function RoundDown(ByVal value As Double, ByVal precision As Integer) _
	As Double
        Return Round(value, precision, RoundingDirection.Down)
    End Function

    Private Function Round(ByVal value As Double, ByVal precision As Integer, _
	ByVal roundingDirection As RoundingDirection) As Double
        Dim roundingFunction As RoundingFunction
        If roundingDirection = RoundingDireciton.Up Then
            roundingFunction = AddressOf Math.Ceiling
        Else
            roundingFunction = AddressOf Math.Floor
        End If
        value = value * Math.Pow(10, precision)
        value = roundingFunction(value)
        Return value * Math.Pow(10, -1 * precision)
    End Function

End Module

The rounding algorithm is quite simple: Firstly, we shift all the digits we are interested in keeping, to the left of the decimal point. We then either call Math.Floor() or Math.Ceiling() on the result depending on whether we are rounding down or up respectively. Finally, we shift our digits back to the right of the decimal point and return the value.

The method handles values of type Double. You can always add your own overloads to handle values of other types (e.g.: Decimal).

Some Examples

Here are some examples of our code in action:

C#
// C#
static void Main(string[] args)
{
    Console.WriteLine(EnhancedMath.RoundUp(3.141592654, 2)); // Result: 3.15
    Console.WriteLine(EnhancedMath.RoundUp(3.141592654, 3)); // Result: 3.142
    Console.WriteLine(EnhancedMath.RoundDown(3.141592654, 2)); // Result: 3.14
    Console.WriteLine(EnhancedMath.RoundDown(3.141592654, 3)); // Result: 3.141
    Console.Read();
}
VB.NET
' Visual Basic
Sub Main(ByVal args() As String)
    Console.WriteLine(EnhancedMath.RoundUp(3.141592654, 2)) ' Result: 3.15
    Console.WriteLine(EnhancedMath.RoundUp(3.141592654, 3)) ' Result: 3.142
    Console.WriteLine(EnhancedMath.RoundDown(3.141592654, 2)) ' Result: 3.14
    Console.WriteLine(EnhancedMath.RoundDown(3.141592654, 3)) ' Result: 3.141
    Console.Read()
End Sub

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionRounding double does not always give expected result? Pin
shalomshachne14-Aug-18 2:34
shalomshachne14-Aug-18 2:34 
BugBE AWARE Pin
Member 95725944-Nov-12 23:54
Member 95725944-Nov-12 23:54 
GeneralMy vote of 5 Pin
Brad16023-Apr-12 18:58
Brad16023-Apr-12 18:58 
GeneralMy vote of 5 Pin
Anthony Daly7-Jun-11 8:34
Anthony Daly7-Jun-11 8:34 
GeneralRounding modes Pin
supercat919-May-11 5:46
supercat919-May-11 5:46 
There are at least seven rounding modes I've seen used in different contexts:

    Round toward zero
    Round away from zero
    Round toward positive infinity
    Round toward negative infinity
    Round toward nearest value, with bias toward zero
    Round toward nearest value, with bias toward positive infinity
    Round toward nearest value, with bias toward nearest even value.

The use of delegates is cute, but I don't think this is a good use. One could just as well perform the 'if' test after one has multiplied the value by the appropriate power of ten, and simply have the 'if' test perform the appropriate computation directly. Delegates are generally worthwhile if it's necessary to do a significant amount of stuff between making a decision and acting upon it, but not when the action could immediately follow the decision.
GeneralMy vote of 5 Pin
T_uRRiCA_N12-May-11 19:49
professionalT_uRRiCA_N12-May-11 19:49 
GeneralRe: My vote of 5 Pin
MBigglesworth7918-May-11 13:19
MBigglesworth7918-May-11 13:19 
GeneralMy vote of 5 Pin
Avijit Jana10-May-11 8:38
Avijit Jana10-May-11 8:38 
General5 but for a different topic! Pin
cjb1108-May-11 21:27
cjb1108-May-11 21:27 
GeneralRe: 5 but for a different topic! Pin
MBigglesworth799-May-11 0:05
MBigglesworth799-May-11 0:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.