【发布时间】:2020-04-08 16:48:39
【问题描述】:
我知道浮点加法不是关联的:(a + b) + c 通常不等于a + (b + c)。所以这个求和算法可以根据输入的顺序给出不同的结果:
float naive_sum(float[] input) {
float accumulator = 0;
for (float x : input) {
accumulator += x;
}
return accumulator;
}
是否可以使这个顺序独立,以便即使输入被打乱也返回相同的结果?我不是想减少舍入误差:我只是希望它与订单无关。
一个想法是先对输入进行排序:
float sort_sum(float[] input) {
return naive_sum(sort(input));
}
sort 不必将浮点数按数字顺序排列;它只需要满足sort(input) == sort(shuffle(input))。我认为这可行,但它不再像 naive_sum 那样是恒定的空间和线性时间。
另一个想法是让累加器成为一个巨大的整数类型:大到足以容纳任何浮点数而无需四舍五入。如果浮点数具有 11 位指数,则需要大约 2^11 位,即大约 2000 位。
float fixedpoint_sum(float[] input) {
int2048 accumulator = 0;
for (float x : input) {
accumulator += float_to_fixed(x);
}
return fixed_to_float(accumulator);
}
现在又是常数空间和线性时间,但是有这么大的累加器,可能是一个非常慢的线性时间。 :)
对于浮点数的顺序无关求和是否有任何实用算法?
【问题讨论】:
-
是否可以接受特定于 Java 的解决方案?
-
累加器方法可能没有你想象的那么糟糕:获取指数,用它索引累加器,加法,然后进位。进位偶尔会传播很多,但很少传播,除非应用程序设计中的某些东西导致它。然而,除了受累加器宽度限制之外,它并不是真正的恒定时间。也就是说,发生多少次进位会影响时间。但它通常很小。
标签: algorithm floating-point non-deterministic