哪种方式更准确?

时间:2012-09-05 12:58:28

标签: c# algorithm precision double-precision numerical-computing

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

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

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

免责声明:我要举例说明的所有数字都不准确,但要说明幕后发生的事情的原则。

我们来看两个案例:

(1)int1 = 1000, int2= 3, double = 3.0 第一种方法将为您提供:(1000.0 / 3) * 3 == 333.33333 * 3.0 == 999.999...
第二个会给(1000 * 3.0) / 3 == 3000 / 3 == 1000
在这种情况下 - 第二种方法更准确

(2)int1 = 2, int2 = 2, double = Double.MAX_VALUE
第一个将产生(2.0 / 2) * Double.MAX_VALUE == 1 * Double.MAX_VALUE == Double.MAX_VALUE
虽然第二个会给(2 * Double.MAX_VALUE) / 2 - 这会导致(在Java中)Infinity,但我不确定这个案例的双重标准是什么,如果它可能溢出或是它总是无限 - 但它绝对是一个问题。
因此,在这种情况下 - 第一种方法更准确

如果integerlongdoublefloat,则事情可能会更复杂,因为有double的长值无法由{double表示1}} s,因此在这种情况下,大double个值可能会失去准确性,并且在任何情况下 - 大int1值都不太准确。

结论特定于域名哪个更好。在某些情况下,第一种方法应该更好,而在第一种方法中应该更好。这实际上取决于int2double和{{1}}的值。
然而--AFAIK,一般的经验法则是双精度运算保持计算尽可能小(不要创建大数字,然后减少它们,尽可能保持它们最小)。此问题称为loss of significant digits

答案 2 :(得分: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;
}