我需要将数值范围划分为具有相同长度的某些段。但我无法确定哪种方式更准确。例如:
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 * double
或int1 * 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);
}
}
答案 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
,但我不确定这个案例的双重标准是什么,如果它可能溢出或是它总是无限 - 但它绝对是一个问题。
因此,在这种情况下 - 第一种方法更准确。
如果integer
为long
或double
为float
,则事情可能会更复杂,因为有double
的长值无法由{double
表示1}} s,因此在这种情况下,大double
个值可能会失去准确性,并且在任何情况下 - 大int1
值都不太准确。
结论:特定于域名哪个更好。在某些情况下,第一种方法应该更好,而在第一种方法中应该更好。这实际上取决于int2
,double
和{{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;
}