In this article, we will explore C# possibilities when we want to round down a number to the nearest integer. We will do that by testing several methods, which would probably first cross the minds of developers when solving this task.

To download the source code for this article, you can visit our GitHub repository.

We will explore Math.Floor(), Math.Truncate(), Math.Round() with different MitpointRounding modes, Convert.ToInt32(), casting to an integer, and subtraction using the modulo operator. We will test each of those methods with different edge cases.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

Set up the Stage

We will define an array of double values. Two are halfway to integer values, two are closer to bigger integers, and two are closer to smaller integers. With these examples, we are covering all possible different outputs of tested methods. 

Here is the defined array:

var testCases = new double[] { 2.5, 1.75, 1.5, 1.25, -1.25, -1.5, -1.75, -2.5 };

We want to round down numbers from the test cases to the nearest integer number. That means that rounding the numbers halfway from integers or those closer to bigger integers results in a smaller integer. For example, both 1.75 and 1.25 are rounded down to 1. And for -1.25 and -1.75 the next smaller integer is -2.

Our desired results for the example test cases look like this:

{ 2, 1, 1, 1, -2, -2, -2, -3 };

Use Math.Floor() Method to Round Down a Number to a Nearest Integer

The Math.Floor() method returns the largest integral value, less or equal to the parameter value. The returned value will be double, so we have to convert it to an integer:

public static int[] RoundDownUsingMathFloor(double[] testCases)
{
    var results = new int[testCases.Length];

    for (var cnt = 0; cnt < testCases.Length; cnt++)
    {
        results[cnt] = (int)Math.Floor(testCases[cnt]);
    }

    return results;
}

When we call it with each of the defined input values, the results are: 

Round down using Math.Floor():
Rounding 2,5 results in 2 (desired result: 2)
Rounding 1,75 results in 1 (desired result: 1)
Rounding 1,5 results in 1 (desired result: 1)
Rounding 1,25 results in 1 (desired result: 1)
Rounding -1,25 results in -2 (desired result: -2)
Rounding -1,5 results in -2 (desired result: -2)
Rounding -1,75 results in -2 (desired result: -2)
Rounding -2,5 results in -3 (desired result: -3)

Math.Floor() is indeed returning values rounded down to the nearest integer.

Math.Truncate() Method

Math.Truncate() returns an integral part of a number. It returns double, so we need to cast results to an integer:

public static int[] RoundDownUsingMathTruncate(double[] testCases)
{
    var results = new int[testCases.Length];

    for (var cnt = 0; cnt < testCases.Length; cnt++)
    {
        results[cnt] = (int)Math.Truncate(testCases[cnt]);
    }

    return results;
}

The results of our testing are:

Round down using Math.Truncate():
Rounding 2,5 results in 2 (desired result: 2)
Rounding 1,75 results in 1 (desired result: 1)
Rounding 1,5 results in 1 (desired result: 1)
Rounding 1,25 results in 1 (desired result: 1)
Rounding -1,25 results in -1 (desired result: -2)
Rounding -1,5 results in -1 (desired result: -2)
Rounding -1,75 results in -1 (desired result: -2)
Rounding -2,5 results in -2 (desired result: -3)

We can see that it returns the expected result only for positive numbers.

Use Math.Round() Method to Round Down a Number to the Nearest Integer

Math.Round() rounds the value to the nearest integral value or the provided number of fractional digits. It will return double, so we must cast the result to int.

This method comes with several overloads. Some have a MidpointRounding parameter that determines the rounding convention or modes. The value of this parameter affects only results for numbers halfway between two integer values (values 2.5, 1.5, -1.5, and -2.5 from our example). .NET defines five possible values for it, and we will explore each.

MidpointRounding.ToEven Mode

This is the default mode. When the number is halfway between two integers, this mode will round it to the nearest even number. This strategy is also known as banker’s rounding:

public static int[] RoundDownUsingMathRoundWithToEvenMode(double[] testCases)
{
    var results = new int[testCases.Length];

    for (var cnt = 0; cnt < testCases.Length; cnt++)
    {
        results[cnt] = (int)Math.Round(testCases[cnt], MidpointRounding.ToEven);
    }

    return results;
}

Here are the results:

Round down using Math.Round() with ToEven mode:
Rounding 2,5 results in 2 (desired result: 2)
Rounding 1,75 results in 2 (desired result: 1)
Rounding 1,5 results in 2 (desired result: 1)
Rounding 1,25 results in 1 (desired result: 1)
Rounding -1,25 results in -1 (desired result: -2)
Rounding -1,5 results in -2 (desired result: -2)
Rounding -1,75 results in -2 (desired result: -2)
Rounding -2,5 results in -2 (desired result: -3)

MidpointRounding.AwayFromZero Mode

AwayFromZero mode will round the number to the nearest integer. When the number is halfway, this mode will round it to the nearest number away from zero:

public static int[] RoundDownUsingMathRoundWithAwayFromZeroMode(double[] testCases)
{
    var results = new int[testCases.Length];

    for (var cnt = 0; cnt < testCases.Length; cnt++)
    {
        results[cnt] = (int)Math.Round(testCases[cnt], MidpointRounding.AwayFromZero);
    }

    return results;
}

Results are:

Round down using Math.Round() with AwayFromZero mode:
Rounding 2,5 results in 3 (desired result: 2)
Rounding 1,75 results in 2 (desired result: 1)
Rounding 1,5 results in 2 (desired result: 1)
Rounding 1,25 results in 1 (desired result: 1)
Rounding -1,25 results in -1 (desired result: -2)
Rounding -1,5 results in -2 (desired result: -2)
Rounding -1,75 results in -2 (desired result: -2)
Rounding -2,5 results in -3 (desired result: -3)

MidpointRounding.ToZero Mode

ToZero rounding mode will return values toward zero:

public static int[] RoundDownUsingMathRoundWithToZeroMode(double[] testCases)
{
    var results = new int[testCases.Length];

    for (var cnt = 0; cnt < testCases.Length; cnt++)
    {
        results[cnt] = (int)Math.Round(testCases[cnt], MidpointRounding.ToZero);
    }

    return results;
}

Results are:

Round down using Math.Round() with ToZero mode:
Rounding 2,5 results in 2 (desired result: 2)
Rounding 1,75 results in 1 (desired result: 1)
Rounding 1,5 results in 1 (desired result: 1)
Rounding 1,25 results in 1 (desired result: 1)
Rounding -1,25 results in -1 (desired result: -2)
Rounding -1,5 results in -1 (desired result: -2)
Rounding -1,75 results in -1 (desired result: -2)
Rounding -2,5 results in -2 (desired result: -3)

With this mode, desired results are only for positive values. 

MidpointRounding.ToNegativeInfinity Mode

This mode will round numbers down in the direction of negative infinity:

public static int[] RoundDownUsingMathRoundWithToNegativeInfinityMode(double[] testCases)
{
    var results = new int[testCases.Length];

    for (var cnt = 0; cnt < testCases.Length; cnt++)
    {
        results[cnt] = (int)Math.Round(testCases[cnt], MidpointRounding.ToNegativeInfinity);
    }

    return results;
}

Here are the results:

Round down using Math.Round() with ToNegativeInfinity mode:
Rounding 2,5 results in 2 (desired result: 2)
Rounding 1,75 results in 1 (desired result: 1)
Rounding 1,5 results in 1 (desired result: 1)
Rounding 1,25 results in 1 (desired result: 1)
Rounding -1,25 results in -2 (desired result: -2)
Rounding -1,5 results in -2 (desired result: -2)
Rounding -1,75 results in -2 (desired result: -2)
Rounding -2,5 results in -3 (desired result: -3)

The results are the same as desired results. 

MidpointRounding.ToPositiveInfinity Mode

ToPositiveInfinity will round numbers up in the direction of positive infinity:

public static int[] RoundDownUsingMathRoundWithToPositiveInfinityMode(double[] testCases)
{
    var results = new int[testCases.Length];

    for (var cnt = 0; cnt < testCases.Length; cnt++)
    {
        results[cnt] = (int)Math.Round(testCases[cnt], MidpointRounding.ToPositiveInfinity);
    }

    return results;
}

Results are:

Round down using Math.Round() with ToPositiveInfinity mode:
Rounding 2,5 results in 3 (desired result: 2)
Rounding 1,75 results in 2 (desired result: 1)
Rounding 1,5 results in 2 (desired result: 1)
Rounding 1,25 results in 2 (desired result: 1)
Rounding -1,25 results in -1 (desired result: -2)
Rounding -1,5 results in -1 (desired result: -2)
Rounding -1,75 results in -1 (desired result: -2)
Rounding -2,5 results in -2 (desired result: -3)

Use Convert.ToInt32() to Round Down a Number

Convert.ToInt32() converts the value to a 32-bit signed integer:

public static int[] RoundDownUsingConvertToInt32(double[] testCases)
{
    var results = new int[testCases.Length];

    for (var cnt = 0; cnt < testCases.Length; cnt++)
    {
        results[cnt] = Convert.ToInt32(testCases[cnt]);
    }

    return results;
}

And here are the results:

Round down using Convert.ToInt32():
Rounding 2,5 results in 2 (desired result: 2)
Rounding 1,75 results in 2 (desired result: 1)
Rounding 1,5 results in 2 (desired result: 1)
Rounding 1,25 results in 1 (desired result: 1)
Rounding -1,25 results in -1 (desired result: -2)
Rounding -1,5 results in -2 (desired result: -2)
Rounding -1,75 results in -2 (desired result: -2)
Rounding -2,5 results in -2 (desired result: -3)

We can notice that Convert.ToInt32() gives the same results as Math.Round() with MidpointRounding.ToEven mode.

Cast to an Integer

Explicit conversion, or casting, instructs the compiler to which type we want to convert the value. In our case, we are using (int):

public static int[] RoundDownUsingCasting(double[] testCases)
{
    var results = new int[testCases.Length];

    for (var cnt = 0; cnt < testCases.Length; cnt++)
    {
        results[cnt] = (int)testCases[cnt];
    }

    return results;
}

Results are: 

Round down using casting:
Rounding 2,5 results in 2 (desired result: 2)
Rounding 1,75 results in 1 (desired result: 1)
Rounding 1,5 results in 1 (desired result: 1)
Rounding 1,25 results in 1 (desired result: 1)
Rounding -1,25 results in -1 (desired result: -2)
Rounding -1,5 results in -1 (desired result: -2)
Rounding -1,75 results in -1 (desired result: -2)
Rounding -2,5 results in -2 (desired result: -3)

We notice that casting to an integer value gives the same results as Math.Round() with MidpointRounding.ToZero mode. Casting gives desired results only for positive values.

Calculate Subtraction With Modulo to Round Down a Number to the Nearest Integer

The idea here is to subtract the result of the modulo (%) operator with 1 (resulting in a fractional part of the input number) from the input number. The result is an integral number:

public static int[] RoundDownUsingSubtractionWithModulo(double[] testCases)
{
    var results = new int[testCases.Length];

    for (var cnt = 0; cnt < testCases.Length; cnt++)
    {
        results[cnt] = (int)(testCases[cnt] - (testCases[cnt] % 1));
    }

    return results;
}

Results are:

Round down using subtraction with modulo:
Rounding 2,5 results in 2 (desired result: 2)
Rounding 1,75 results in 1 (desired result: 1)
Rounding 1,5 results in 1 (desired result: 1)
Rounding 1,25 results in 1 (desired result: 1)
Rounding -1,25 results in -1 (desired result: -2)
Rounding -1,5 results in -1 (desired result: -2)
Rounding -1,75 results in -1 (desired result: -2)
Rounding -2,5 results in -2 (desired result: -3)

This approach will give the same result as Math.Round() with MidpointRounding.ToZero and casting to an integer. The method returns desired results only for positive numbers.

Conclusion

In this article, we’ve seen that only Math.Floor() and Math.Round() with MidpointRounding.NegativeInfinity will give desired results. Math.Truncate(), Math.Round() with MidpointRounding.ToZero and subtraction with modulo will give desired results only for positive numbers. All other methods won’t produce desired results.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!