2015-06-24 5 views
1

Проблема. У меня строка двойная «0.4 0.3 2.1 и т. Д.». Мне нужно зациклиться на этом списке и подсчитать случаи каждого числа.For-loop with double in Java

Я использовал

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); 
} 

где значения является строка и orderValues ​​ является TreeMap.

После этого я должен добавить к TreeMap все отсутствующие значения от 0 до max key Значение с 0 встречей. Поэтому я использую

for(double i = 0; i<=orderValues.lastKey(); i+=0.1) { 
    if (orderValues.get(new Double(i))==null) { 
     orderValues.put(i,0); 
    } 
} 

Проблема заключается в итерации на двойной. Мне нужно итерации только на первом десятичном значении двойного значения. Это выход.

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.. 

И, конечно, это проблема (посмотрите на 1.4 и 1.4000000001). Как я могу предотвратить это?

Основная проблема итерацию по двойной 0,1 значения


Как Fixed (благодаря Roel). я изменил для постановки на

for(double i = 0.1; i<=orderValues.lastKey(); i=rounding(0.1+i)) { 

и добавлена ​​функция округления

private double rounding(double x) { 
    BigDecimal bd = new BigDecimal(x); 
    bd = bd.setScale(1, RoundingMode.HALF_UP); 
    return bd.doubleValue(); 
} 
+1

Возможный дубликат [Является ли математика с плавающей запятой?] (Http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Dragondraikk

+1

На этой заметке похоже, что вы используете двойные как ключевые значения для карты, которая немного сложна из-за того, что арифметика с плавающей запятой является такой, какой она есть. Возможно, вы захотите рассмотреть возможность использования «BigDecimal» вместо этого, которая также решит вашу итерационную проблему. – Dragondraikk

ответ

1

Вы используете примитив двойной и класса типа Double и есть преобразование происходит между ними, и как они «Обе с плавающей точкой вы видите неточность с плавающей запятой.

1

Недостаток точности двойных типов хорошо известен. Обычно решением является использование BigDecimal. Однако в вашем конкретном случае, поскольку на каждой итерации вы делаете шаг 0,1, вы также можете работать с целыми числами и делить их на 10 при необходимости.

Обратите внимание, что вы также должны изменить способ хранения данных. То есть, использование:

TreeMap<BigDecimal, Integer> 

(or TreeMap<Integer, Integer>) instead of TreeMap<Double, Integer> 

Смотрите также документацию BigDecimal: http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html Это не так просто, как дважды, но гораздо безопаснее.