Problem. I have a String of double "0.4 0.3 2.1 etc". I need to loop in this list and count occurencies of each number.
I used
StringTokenizer stokens = new StringTokenizer(values);
while(stokens.hasMoreTokens()) {
Double tempKey = new Double(stokens.nextToken());
Integer tempCount = orderValues.get(tempKey);
if (tempCount == null)
tempCount = 1;
else
tempCount++;
orderValues.put(tempKey, tempCount);
}
where values is the string and orderValues is a TreeMap.
After this I have to add to the TreeMap all missing values from 0 to max key Value with a 0 occurency. So I use
for(double i = 0; i<=orderValues.lastKey(); i+=0.1) {
if (orderValues.get(new Double(i))==null) {
orderValues.put(i,0);
}
}
The problem is the iteration on the double. I need to iterate just on the first decimal of double value. This is the output.
0.0 => 0
0.1 => 0
0.2 => 0
0.30000000000000004 => 0
0.4 => 0
0.5 => 1
0.6 => 1
0.7 => 0
0.7999999999999999 => 0
0.8999999999999999 => 0
0.9999999999999999 => 0
1.0999999999999999 => 0
1.2 => 2
1.3 => 0
1.4 => 2
1.4000000000000001 => 0
etc..
And of course it's a problem (look at 1.4 and 1.4000000001). How can I prevent this?
The main problem is iterate on double by 0.1 value
How I Fixed (thanks to Roel). I've changed the for statement into
for(double i = 0.1; i<=orderValues.lastKey(); i=rounding(0.1+i)) {
and added the rounding function
private double rounding(double x) {
BigDecimal bd = new BigDecimal(x);
bd = bd.setScale(1, RoundingMode.HALF_UP);
return bd.doubleValue();
}
The lack of precision of double types is well-known. Usually, a solution is to use BigDecimal instead. However in your specific case, since you're stepping 0.1 at each iteration, you could also work with integers, and divide them by 10 when needed.
Note that you should also change the way you store the data. That is, use:
See also the documentation of BigDecimal: http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html It's not as easy to use as double, but much safer.