我有一些代码在 float 映射上计算线性组合,并遇到了使用复制构造函数的有趣副作用。
如果我计算两个 map 中值的线性组合并将其与使用这些 map 的两个副本中的值计算的线性组合进行比较,计算结果实际上略有不同(在10^-7) 结果似乎是浮点精度。
为什么会这样?
下面是一些示例代码:
import java.util.*;
public class WTF {
public static void main(String[] args) {
Random rand = new Random();
for (int c = 0; c < 1000; c++) {
Map<String, Float> weights = new HashMap<String, Float>();
Map<String, Float> values = new HashMap<String, Float>();
for (int j = 0; j < 10; j++) {
weights.put("sig" + j, Float.valueOf(rand.nextFloat()));
values.put("sig" + j, Float.valueOf(rand.nextFloat()));
}
Map<String, Float> weightsCopy = new HashMap<String, Float>(weights);
Map<String, Float> valuesCopy = new HashMap<String, Float>(values);
float score1 = getScore(weights, values);
float score2 = getScore(weightsCopy, valuesCopy);
if (score1 != score2) {
System.out.println(score1-score2);
}
}
}
public static float getScore(Map<String, Float> weights, Map<String, Float> values) {
float score = 0.0f;
for (String name : weights.keySet()) {
Float weight = weights.get(name);
Float value = values.get(name);
score += weight.floatValue() * value.floatValue();
}
return score;
}
}
更新:
同样的问题也适用于 putAll
操作。使用它来“复制”HashMap
会导致相同的浮点精度问题。
最佳答案
map 中的顺序发生变化,导致操作以不同的顺序运行。简单计算的输出变化示例(注意翻转的 d 和 e):
class WTF {
public static void main(String[] args) {
final float a = 0.42890447f * 0.37233013f;
final float b = 0.2648958f * 0.05867535f;
final float c = 0.8928169f * 0.7546882f;
final float d = 0.0039135218f * 0.59395087f;
final float e = 0.9114683f * 0.33522367f;
System.out.println(a + b + c + d + e);
System.out.println(a + b + c + e + d);
}
}
关于java - Java HashMap 拷贝构造函数为什么会影响 float 精度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9624869/