1

我需要将一个数字范围划分为一些具有相同长度的段。但我无法决定哪种方式更准确。例如:

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;
}

大约是(double)int1 / int2 * doubleint1 * double / int2。哪种方式更准确?我应该使用哪种方式?

更新

以下代码将显示差异:

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);
    }
}
4

3 回答 3

1

两者都不是特别快,因为编译器或 JIT 进程可能会重新排序操作以提高效率。

于 2012-09-05T13:00:41.590 回答
1

免责声明:我将作为示例给出的所有数字都不准确,但显示了幕后发生的事情的原理。

我们来看两个案例:

(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.

于 2012-09-06T18:34:51.127 回答
0

也许我误解了您的要求,但为什么要在循环内进行任何除法/乘法?也许这会得到相同的结果:

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;
}
于 2012-09-05T13:06:24.110 回答