46

How can I multiply two decimals and round the result down to 2 decimal places?

For example if the equation is 41.75 x 0.1 the result will be 4.175. If I do this in c# with decimals it will automatically round up to 4.18. I would like to round down to 4.17.

I tried using Math.Floor but it just rounds down to 4.00. Here is an example:

Math.Floor (41.75 * 0.1);
startupsmith
  • 5,554
  • 10
  • 50
  • 71

9 Answers9

69

The Math.Round(...) function has an Enum to tell it what rounding strategy to use. Unfortunately the two defined won't exactly fit your situation.

The two Midpoint Rounding modes are:

  1. AwayFromZero - When a number is halfway between two others, it is rounded toward the nearest number that is away from zero. (Aka, round up)
  2. ToEven - When a number is halfway between two others, it is rounded toward the nearest even number. (Will Favor .16 over .17, and .18 over .17)

What you want to use is Floor with some multiplication.

var output = Math.Floor((41.75 * 0.1) * 100) / 100;

The output variable should have 4.17 in it now.

In fact you can also write a function to take a variable length as well:

public decimal RoundDown(decimal i, double decimalPlaces)
{
   var power = Convert.ToDecimal(Math.Pow(10, decimalPlaces));
   return Math.Floor(i * power) / power;
}
Aren
  • 54,668
  • 9
  • 68
  • 101
  • 2
    Actualy, it should work using the `Math.Round Method (Decimal, Int32, MidpointRounding)` overload (check http://stackoverflow.com/questions/13522095/rounding-down-to-2-decimal-places-in-c-sharp) – Mat M Jan 24 '14 at 14:29
  • i * power is an error. You meant double there might be. – sandeep talabathula May 12 '16 at 02:52
  • You cant multiply a double with a decimal – Ruan Jun 28 '17 at 08:46
  • The MidpointRounding overload could solve the issue of .5 rounding down instead of up (if there were a strategy called "TowardZero"), but I believe the asker used a poor example. Their question indicated they wanted all numbers to round down to 2 digits. So 4.179999999 would be 4.17. If you only want midpoints to round down, you should use that overload, but if you want all to round down, you need the technique above or similar techniques in other answers. – Brandon Barkley Jan 09 '19 at 08:00
  • 1
    This was almost 8 years ago. Is this still the best answer? – softarn Jul 02 '20 at 07:37
  • Heads up! Depending on the device, this might lead to accuracy issues. When trying to apply this function to the value 10.40 at 2 decimal places, I got 10.39 on an Android device using Xamarin. – Jonathan Queipo Mar 02 '21 at 20:06
19
public double RoundDown(double number, int decimalPlaces)
{
     return Math.Floor(number * Math.Pow(10, decimalPlaces)) / Math.Pow(10, decimalPlaces);
}
sashkello
  • 17,306
  • 24
  • 81
  • 109
  • 1
    Heads up! Depending on the device, this might lead to accuracy issues. When trying to apply this function to the value 10.40 at 2 decimal places, I got 10.39 on an Android device using Xamarin. – Jonathan Queipo Mar 02 '21 at 20:07
18

As of .NET Core 3.0 and the upcoming .NET Framework 5.0 the following is valid

Math.Round(41.75 * 0.1, 2, MidpointRounding.ToZero)
Sirhc
  • 518
  • 7
  • 13
  • 1
    I was hesitant to use this because the documentation I read describes "a number *halfway* between two others" but this does correctly answer the question depending on what you want with negatives. One might also consider ToNegativeInfinity – SteveC Mar 09 '22 at 22:52
9

There is no native support for precision floor/ceillin in c#.

You can however mimic the functionality by multiplying the number, the floor, and then divide by the same multiplier.

eg,

decimal y = 4.314M;
decimal x = Math.Floor(y * 100) / 100;  // To two decimal places (use 1000 for 3 etc)
Console.WriteLine(x);  // 4.31

Not the ideal solution, but should work if the number is small.

Kami
  • 19,134
  • 4
  • 51
  • 63
1

One more solution is to make rounding toward zero from rounding away from zero. It should be something like this:

    static decimal DecimalTowardZero(decimal value, int decimals)
    {
        // rounding away from zero
        var rounded = decimal.Round(value, decimals, MidpointRounding.AwayFromZero);

        // if the absolute rounded result is greater 
        // than the absolute source number we need to correct result
        if (Math.Abs(rounded) > Math.Abs(value))
        {
            return rounded - new decimal(1, 0, 0, value < 0, (byte)decimals);
        }
        else
        {
            return rounded;
        }
    }
SLenik
  • 815
  • 1
  • 8
  • 15
1

If you want to round down any double to specific decimal places, if doesn´t matter if is the midpoint, you can use:

    public double RoundDownDouble(double number, int decimaPlaces)
    {
        var tmp = Math.Pow(10, decimaPlaces);
        return Math.Truncate(number * tmp) / tmp;
    }
0

This is my Float-Proof Round Down.

    public static class MyMath
{
    public static double RoundDown(double number, int decimalPlaces)
    {
        string pr = number.ToString();
        string[] parts = pr.Split('.');
        char[] decparts = parts[1].ToCharArray();
        parts[1] = "";
        for (int i = 0; i < decimalPlaces; i++)
        {
            parts[1] += decparts[i];
        }
        pr = string.Join(".", parts);
        return Convert.ToDouble(pr);
    }
}
lou34964
  • 1
  • 3
0

I've found that the best method is to use strings; the binary vagaries of Math tend to get things wrong, otherwise. One waits for .Net 5.0 to make this fact obsolete. No decimal places is a special case: you can use Math.Floor for that. Otherwise, we ToString the number with one more decimal place than is required, then parse that without its last digit to get the answer:

/// <summary>
/// Truncates a Double to the given number of decimals without rounding
/// </summary>
/// <param name="D">The Double</param>
/// <param name="Precision">(optional) The number of Decimals</param>
/// <returns>The truncated number</returns>
public static double RoundDown(this double D, int Precision = 0)
{
  if (Precision <= 0) return Math.Floor(D);
  string S = D.ToString("0." + new string('0', Precision + 1));
  return double.Parse(S.Substring(0, S.Length - 1));
}
Dan Sutton
  • 21
  • 3
0

Simply Math.Round() solves this problem and fits the situation with passing a precision parameter and MidpointRounding parameter to the method.

The short answer is:
Math.Round(41.75 * 0.1, 2, MidpointRounding.ToNegativeInfinity)
which the second parameter is the precision and the third is the rounding strategy.

If you want to know exactly how Math.Round works you can read the full explanation here: How do you round a number to two decimal places in C#?

mahdi yousefi
  • 807
  • 1
  • 9
  • 15