0

As in question, how to round up in C# with n.5 value (n is integer):

1.5 -> 2
2.5 -> 3
-1.5 -> -1
-2.5 -> -2

1.4 -> 1
1.6 -> 2
-1.4 -> -1
-1.6 -> -2

I search but in C#, Math.Round only support MidpointRounding.AwayFromZero and MidpointRounding.ToEven. Maybe programmer should do trick to round a number in normal life thought (not banking or academic thought...)?

That expected result is as in Javascript, value n.5 always round up to (+)infinite +∞

Pham X. Bach
  • 5,284
  • 4
  • 28
  • 42
  • @AluanHaddad: Try `Math.Round(-3.5)`. (.NET rounds to even by default.) – Ry- Oct 17 '17 at 02:47
  • @AluanHaddad In C#, default round is **ToEven**. So `-2.5 -> -2` and `-1.5 -> -2` too. You could try it in http://rextester.com/ – Pham X. Bach Oct 17 '17 at 02:49
  • 1
    Related [SO](https://stackoverflow.com/questions/311696/why-does-net-use-bankers-rounding-as-default) and [Math.SE](https://mathematica.stackexchange.com/questions/2116/why-round-to-even-integers). Round half-up isn't really "normal life", it's just what's usually taught on primary school. – Martheen Oct 17 '17 at 03:07
  • Do your numbers always have one digit after the decimal place? – Ry- Oct 17 '17 at 03:23
  • @Ryan For C#, It should apply for any number of fractional digits, e.g `2.35 -> 2.4`. Thank you. – Pham X. Bach Oct 17 '17 at 03:38
  • @Martheen Yes, I know Microsoft have reason to default their `MidpointRounding`. And I ask Just because it's not expected by us and our customer :( – Pham X. Bach Oct 17 '17 at 03:46
  • @PhamX.Bach Are you using binary floating-point (`double` / `Double`)? If so, rounding for a nonzero number of fractional digits is going to be problematic. E.g., do you want the `double` value `2.65d`, rounded to 1 place, to give `2.6` or `2.7`? – Mark Dickinson Oct 17 '17 at 12:17

2 Answers2

1

Try this :)

[TestFixture]
public class TestClass
{
    int NumberOfDecimalDigits(double d)
    {
        var text = Math.Abs(d).ToString();
        int integerPlaces = text.IndexOf('.');
        int decimalPlaces = text.Length - integerPlaces - 1;
        return decimalPlaces;
    }

    double GetDelta(int numberOfDecimalDigits)
    {
        var deltaStringBuilder = new StringBuilder();
        deltaStringBuilder.Append("1");
        for (int i = 0; i < numberOfDecimalDigits; i++)
        {
            deltaStringBuilder.Append("0");
        }


        double delta = 1 / double.Parse(deltaStringBuilder.ToString());
        return delta;
    }

double Round(double value, int digits)
        {
            if (value > 0)
            {
                return Math.Round(value, digits, MidpointRounding.AwayFromZero);
            }
            if (value < 0)
            {
                var numberOfDecimalDigits = NumberOfDecimalDigits(value);
                double delta = GetDelta(numberOfDecimalDigits);
                return Math.Round(value + delta, digits, MidpointRounding.AwayFromZero);
            }

            return value;
        }

    double Round(double value)
    {
        if (value > 0)
        {
            return Math.Round(value, MidpointRounding.AwayFromZero);
        }
        if (value < 0)
        {
            var numberOfDecimalDigits = NumberOfDecimalDigits(value);
            double delta = GetDelta(numberOfDecimalDigits);
            return Math.Round(value + delta, MidpointRounding.AwayFromZero);
        }

        return value;
    }
    [Test]
    public void TestMethod()
    {
        Assert.AreEqual(Round(1), 1);
        Assert.AreEqual(Round(1.9), 2);
        Assert.AreEqual(Round(1.5), 2);
        Assert.AreEqual(Round(2.5), 3);

        Assert.AreEqual(Round(-1), -1);
        Assert.AreEqual(Round(-2.9), -3);

        Assert.AreEqual(Round(-1.5), -1);
        Assert.AreEqual(Round(-2.5), -2);
        Assert.AreEqual(Round(1.4), 1);
        Assert.AreEqual(Round(1.6), 2);

        Assert.AreEqual(Round(-1.4), -1);
        Assert.AreEqual(Round(-1.6), -2);
        Assert.AreEqual(Round(-1.55), -2);

        Assert.AreEqual(Round(-1.6666), -2);
        Assert.AreEqual(Round(-0.9999999), -1);
        Assert.AreEqual(Round(-0.001), 0);

        Assert.AreEqual(Round(2.35, 1), 2.4);
        Assert.AreEqual(Round(-2.35, 1), -2.3);

    }
Dan Nguyen
  • 1,308
  • 6
  • 17
1

Here's a version which passes all your test cases.

static void Main(string[] args)
    {
        Round(double.Epsilon, 0);
        Round(0-double.Epsilon, 0);

        Round(1 + double.Epsilon, 1);
        Round(1 - double.Epsilon, 1);


        Round(1.5, 2);
        Round(2.5, 3);
        Round(-1.5, -1);
        Round(-2.5, -2);

        Round(1.4, 1);
        Round(1.6, 2);
        Round(-1.4, -1);
        Round(-1.6, -2);
    }

    private static void Round(double v1, int v2)
    {
        var equal = (MyRound(v1) == v2) ? "==" : "!=";
        Console.WriteLine($"Math.Round({v1}) {equal} {v2}, it's {MyRound(v1)}");
    }

    private static double MyRound(double v1)
    {
        return (v1 < 0)
            ? 0 - Math.Round(Math.Abs(v1)-0.1)
            : Math.Round(v1, MidpointRounding.AwayFromZero );
    }

Output:

Math.Round(4.94065645841247E-324) == 0, it's 0
Math.Round(-4.94065645841247E-324) == 0, it's 0
Math.Round(1) == 1, it's 1
Math.Round(1) == 1, it's 1
Math.Round(1.5) == 2, it's 2
Math.Round(2.5) == 3, it's 3
Math.Round(-1.5) == -1, it's -1
Math.Round(-2.5) == -2, it's -2
Math.Round(1.4) == 1, it's 1
Math.Round(1.6) == 2, it's 2
Math.Round(-1.4) == -1, it's -1
Math.Round(-1.6) == -2, it's -2
tymtam
  • 31,798
  • 8
  • 86
  • 126