3

I am experimenting with the Math.Round class and I am having problems getting it to do what I want it to do. Basically I have the following code:

double test = 1.675;
double rounded = (double)Math.Round((decimal)test, 2, MidpointRounding.ToEven);
Console.Write(rounded);
Console.ReadKey();

I want rounded to be 1.67, where 1.675 is rounded down to 1.67. Instead, my current output is:

1.68

I thought MidpointRounding.ToEven forced it to round to the nearest even (.005 -> .000)?

Grant Winney
  • 65,241
  • 13
  • 115
  • 165
Giardino
  • 1,367
  • 3
  • 10
  • 30
  • 0.1 *is* even, so .005 would round to .01 – Cilan Mar 06 '14 at 01:13
  • How would I get 1.675 to round to 1.67 then? – Giardino Mar 06 '14 at 01:15
  • You might need to use Math.Floor – AD.Net Mar 06 '14 at 01:16
  • 6
    "I thought MidpointRounding.ToEven forced it to round to the nearest even"- it does. In your case the choices are 1.67 and 1.68. The last digit of 1.68 is even, so it goes to that. If you were doing 1.685, it would round down to 1.68. The type of rounding you're asking for isn't available in the API, so you'll have to fake it with Floor and some division. – Tim Mar 06 '14 at 01:21

4 Answers4

1
  double test = 1.675;
  double rounded = Math.Floor(test * 100) / 100;
  Console.WriteLine(rounded);

This would meet your requirements. Is there anything more specific?

jdphenix
  • 15,022
  • 3
  • 41
  • 74
  • Well, I would be processing more than just one double with the final application. This solution would work for 1.675, but for doubles such as 5.41875, it would round it to 5.41 instead of 5.42 like it should. Basically I just want it to always round down when there is a five (.15, .015, etc). – Giardino Mar 06 '14 at 01:21
  • In that case you'll be rolling your own rounding – jdphenix Mar 06 '14 at 01:40
1

I thought MidpointRounding.ToEven forced it to round to the nearest even (.005 -> .000)?

You've got it wrong. MidpointRounding.ToEven means that it will round you number in a way that the last digit of the result is even.

This is documented here: http://msdn.microsoft.com/de-de/library/system.midpointrounding(v=vs.110).aspx

This should address the "why is it doing that" portion. To the "how to do, what I want":

Use the mode "AwayFromZero" and subtract 0.01 if your value is above zero. (See also: https://stackoverflow.com/a/5166050/1974021)

Community
  • 1
  • 1
DasKrümelmonster
  • 5,816
  • 1
  • 24
  • 45
1

This should provide the desired rounding result:

var test = 1.6765;
var roundToDigits = 2;

var multiplier = Math.Pow(10, roundToDigits);

var roundedValue
    = Equals((test * multiplier) - (int)(test * multiplier), .5)
          ? Math.Floor(test * multiplier) / multiplier
          : Math.Round(test, roundToDigits, MidpointRounding.AwayFromZero);

Results:

  • Rounding 1.6765 to 2 digits returns 1.68.
  • Rounding 1.6765 to 3 digits returns 1.676.
Grant Winney
  • 65,241
  • 13
  • 115
  • 165
0

i had nothing to do right now so for fun i did this...

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine((1.675).CustomRound(2));
            Console.WriteLine((5.41875).CustomRound(2));

            Console.WriteLine((1.67501).CustomRound(2));
            Console.WriteLine((1.67499).CustomRound(2));
            Console.ReadKey();
        }

    }

    public static class fun
    {
        //i looked at math.round with ilspy, they do something like this :-p
        private static readonly double[] pow;

        static fun()
        {
            int max = 16;
            pow = new double[max];

            for (int i = 0; i < max; ++i)
                pow[i] = Math.Pow(10, i);
        }

        public static double CustomRound(this double test, int digits)
        {
            //this seem to be working! :-D
            var fun = test * pow[digits+1];
            var stuff = Math.Floor(test * pow[digits]) * pow[1];
            if ((fun-stuff) == 5)
            {
                return stuff / pow[digits + 1];
            }
            else
            {
                return Math.Round(test, digits, MidpointRounding.AwayFromZero);
            }
        }
    }
}
Fredou
  • 19,848
  • 10
  • 58
  • 113