Npoi Round Formula

869 Views Asked by At

i am new in NPOI while i was working on project i faced strange issue and have no idea how to fix it i am reading fromula data from Excel sheet wich contain Round function and revaluate cell using npoi evaluater XSSFFormulaEvaluator every thing until this moment work fine with me with no problem untill facing this issue in excel sheet i have this formula =round(693.9648;2) the result in excel for this number will be 693.96 but the result with NPOI Evaluator will be 693.97

any one have answer how i can make the evaluter act the same like excel sheet ?!

1

There are 1 best solutions below

0
On BEST ANSWER

I had almost exactly the same problem. The number 481.75478 was being used in the Excel ROUND() function to 2dp. e.g. ROUND(481.75478, 2)

When executing this using the same workbook:

  • Excel would evaluate to 481.75
  • NPOI would evaluate to 481.76

It seemed to be down to the way that NPOI had implemented the Excel ROUND function in C#. In the end I downloaded the source code for the NPOI library, changed the ROUND function to use standard .NET rounding (using MidpointRounding.AwayFromZero as an argument for our purposes) and used my custom DLL.

I downloaded the source code and made the following modifications:

File: \main\SS\Formula\Functions\MathX.cs

Original Code

    public static double Round(double n, int p)
    {
        double retval;

        if (double.IsNaN(n) || double.IsInfinity(n))
        {
            retval = double.NaN;
        }
        else if (double.MaxValue == n)
            return double.MaxValue;
        else if (double.MinValue == n)
            return 0;
        else
        {
            if (p >= 0)
            {
                int temp = (int)Math.Pow(10, p);
                double delta = 0.5;
                int x = p + 1;
                while (x > 0)
                {
                    delta = delta / 10;
                    x--;
                }
                retval = (double)(Math.Round((decimal)(n + delta) * temp) / temp);
            }
            else
            {
                int temp = (int)Math.Pow(10, Math.Abs(p));
                retval = (double)(Math.Round((decimal)(n) / temp) * temp);
            }
        }

        return retval;
    }

Updated Code

    public static double Round(double n, int p)
    {
        double retval;

        if (double.IsNaN(n) || double.IsInfinity(n))
        {
            retval = double.NaN;
        }
        else if (double.MaxValue == n)
            return double.MaxValue;
        else if (double.MinValue == n)
            return 0;
        else
        {
            if (p >= 0)
            {
                // ***** updated to use .NET MidpointRounding.AwayFromZero rounding ***** //
                retval = (double)Math.Round((decimal)n, p, MidpointRounding.AwayFromZero);
            }
            else
            {
                retval = (double)(Math.Round((decimal)(n) / temp) * temp);
            }
        }

        return retval;
    }

Note/Disclaimer

This hasn't been tested yet, so could cause some other unforeseen errors (I'm not sure why the original code was doing some sort of deltafication), but this has fixed the issue I had where rounding was differing between Excel and NPOI. I'll come back and update the answer if I find any issues when the app gets used in anger.

Update 2017-12-04

This has been in production now for a while with no issues. I also realised I should have submitted a PR for this to the project which I now have.