NumberFormat Parse Issue - PullRequest
       11

NumberFormat Parse Issue

3 голосов
/ 16 августа 2011

Я совершенно сбит с толку из-за этой специфической «ошибки», которую я получаю при разборе строки на двойное число.

Я уже настроил NumberFormat свойства и символы.

При передаче строки с 15 цифрами и 2 десятичными знаками (например, str = "333333333333333,33") и синтаксический анализ с Number num = NumberFormat.parse(str) результат опускает цифру.

Фактическое значение num 3.333333333333333E14.

Кажется, что он работает со строками со всеми 1, 2 и 4, хотя ...

Кто-нибудь может просветить меня?

Приветствие Enrico

Ответы [ 2 ]

6 голосов
/ 16 августа 2011

краткий ответ;из-за ошибки округления

(double) 111111111111111.11 != (double) 111111111111111.1

, но

(double) 333333333333333.33 == (double) 333333333333333.3

Если вы хотите большей точности, используйте setParseBigDecimal и parse вернет BigDecimal.


Почему этослучиться?Это потому, что вы находитесь на пределе точности удвоения.17 из них это хорошо, так как это может быть просто представлено.Двойки просто удваивают это, и как двойные хранят степени двойки, каждая сила двух из всех 17 единиц, так что 17 четверок и 17 восьмерок - это хорошо.

Однако 17 тройок занимает на один бит больше, чем двойные должныпредставляют значение, и этот последний бит усекается.Точно так же 17 пятерок, шестерок и девяток также имеют ошибки округления.

double[] ds = {
        111111111111111.11,
        222222222222222.22,
        333333333333333.33,
        444444444444444.44,
        555555555555555.55,
        666666666666666.66,
        777777777777777.77,
        888888888888888.88,
        999999999999999.99};
for (double d : ds) {
    System.out.println(d + " - " + new BigDecimal(d));
}

печатает следующее.double слегка округляется перед печатью, а BigDecimal показывает точные значения, которые представляет двойное число.

1.1111111111111111E14 - 111111111111111.109375
2.2222222222222222E14 - 222222222222222.21875
3.333333333333333E14 - 333333333333333.3125
4.4444444444444444E14 - 444444444444444.4375
5.5555555555555556E14 - 555555555555555.5625
6.666666666666666E14 - 666666666666666.625
7.777777777777778E14 - 777777777777777.75
8.888888888888889E14 - 888888888888888.875
1.0E15 - 1000000000000000
5 голосов
/ 16 августа 2011

Метод DecimalFormat.parse в этом случае вернет Double, который имеет ограниченную точность .

Вы не можете ожидать, что он всегда сможет вернуть число, котороепредставляет ввод точно.

Вы можете использовать BigDecimal.setParseBigDecimal, чтобы позволить формату чисел возвращать BigDecimal из метода разбора.Number способен представлять ваши значения с произвольной точностью.(Спасибо @Peter Lawrey за то, что указал на это!)

...