Search code examples
c#algorithmprecisiondouble-precisionnumerical-computing

Which way is more accurate?


I need to divide a numeric range to some segments that have same length. But I can't decide which way is more accurate. For example:

double r1 = 100.0, r2 = 1000.0, r = r2 - r1;
int n = 30;
double[] position = new double[n];
for (int i = 0; i < n; i++)
{
    position[i] = r1 + (double)i / n * r;
    // position[i] = r1 + i * r / n;
}

It's about (double)int1 / int2 * double or int1 * double / int2. Which way is more accurate? Which way should I use?

Update

The following code will show the difference:

double r1 = 1000.0, r2 = 100000.0, r = r2 - r1;
int n = 300;
double[] position = new double[n];
for (int i = 0; i < n; i++)
{
    double v1 = r1 + (double)i / n * r;
    double v2 = position[i] = r1 + i * r / n;
    if (v1 != v2)
    {
        Console.WriteLine(v2 - v1);
    }
}

Solution

  • Disclaimer: All numbers I am going to give as examples are not exact, but show the principle of what's happening behind the scenes.

    Let's examine two cases:

    (1) int1 = 1000, int2= 3, double = 3.0 The first method will give you: (1000.0 / 3) * 3 == 333.33333 * 3.0 == 999.999...
    While the second will give (1000 * 3.0) / 3 == 3000 / 3 == 1000
    In this scenario - the second method is more accurate.

    (2) int1 = 2, int2 = 2, double = Double.MAX_VALUE
    The first will yield (2.0 / 2) * Double.MAX_VALUE == 1 * Double.MAX_VALUE == Double.MAX_VALUE
    While the second will give (2 * Double.MAX_VALUE) / 2 - which will cause (in Java) to be Infinity, I am not sure what the double standard says about this cases, if it might overflow or is it always infinity - but it is definetly an issue.
    So, in this case - the first method is more accurate.

    The things might go more complicated if the integers are longs or the double is float, since there are long values that cannot be represented by doubles, so loss of accuracy might happen for large double values in this case, and in any case - large double values are less accurate.

    Conclusion: Which is better is domain specific. In some cases the first method should be better and in some the first. It really depends on the values of int1,int2, and double.
    However- AFAIK, the general rule of thumb with double precision ops is keep the calculations as small as possible (Don't create huge numbers and then decrease them back, keep them small as longest as you can). This issue is known as loss of significant digits.