Question

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);
    }
}
Was it helpful?

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.

OTHER TIPS

Neither is particularly faster, since the compiler or the JIT process may reorder the operation for efficiency anyway.

Maybe I misunderstand your requirement but why do any division/multiplication inside the loop at all? Maybe this would get the same results:

decimal r1 = 100.0m, r2 = 1000.0m, r = r2 - r1;
int n = 30;
decimal[] position = new double[n];

decimal diff = r / n;
decimal current = r1;

for (int i = 0; i < n; i++)
{
    position[i] = current;
    current += diff;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top