I had some code calculating a linear combination on maps of floats, and ran into an interesting side-effect of using the copy constructor.
If I calculate the linear combination of values in two maps and compare it with the linear combination calculated using the values in two copies of those maps, the calculations actually have slightly different (in the neighborhood of 10^-7) results due to what appears to be floating point precision.
Why does this happen?
Here’s some sample code:
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;
}
}
UPDATE:
The same issue also applies to the putAll operation. Using that to “copy” a HashMap results in the same floating point precision issues.
The order in the map is changing, causing the operations to be run in a different order. An example of the output changing for simple computation (note the flipped d and e):