2015-05-29 5 views
3

Итак, я много читал об этом, поэтому, пожалуйста, знайте, что я получаю, что число, подобное 0,6, не может быть представлено абсолютно точно, как Java double, но я знаю, что есть версия двойника, которая представляет число 0,6, достаточно близко, чтобы число отображалось как 0,6 вместо примерно 0,6000000000000001 в большинстве интерпретаций конца этого номера (например, включая toString() или маршалинг JSON с использованием библиотеки, такой как Jackson - моя цель).«Практическое» двойное округление в Java

Я ищу механизм принуждения двойника к числу, которое интерпретируется как относительная усеченная точность. Например, если я хочу, чтобы укоротить до 0,1 точности, я хочу что-то, что будет представлять 0.6975265613 укороченный до 0,1 точности в 0,6, а не 0,6000000000000001

Таким образом, в основном делает следующую тестовую работу:

@Test 
public void testRounding() { 

    // prove there is a value that displays cleanly 
    Double cleanValue = 0.6d; 
    assertEquals("0.6", cleanValue.toString()); 

    Double value = 0.6975265613d; 
    Double precision = 0.1d; 

    value = value/precision; 
    value = value.longValue() * precision; 

    // this fails with 0.6000000000000001 
    assertEquals("0.6", value.toString()); 

} 

Я m, используя longValue() для усечения для скорости, но вы получите тот же результат с Math.floor().

Глядя на сырых значений двойных шестигранных, то cleanValue выше: 3fe3333333333333

В то время как результат округления (значение) является: 3fe3333333333334

Мне нужен метод, который будет последовательно дать мне (первая), независимо от точности округления - при условии, что точность не преследует предел точности для типа. Преобразование в String или BigDecimal будет слишком медленным - это аналитическое приложение, где стоимость этих методов x10 будет очень измеримой.

Опять же, понял, что ни шестнадцатеричное число действительно представляет фактическое число 0,6, я просто хочу Java думать, что это 0,6 (т.е. 3fe3333333333333) :)

Спасибо!

+0

Так что вы пытаетесь сделать, это найти целые числа 'x' и' y' такие, что 'х/10^y' как близко к двойному, насколько это возможно. Таким образом, это проблема двумерной оптимизации. – Mysticial

+1

Любая причина, по которой вы не хотите использовать BigDecimal? – BevynQ

+1

Я бы рекомендовал не хранить точность как '0.1d' - вы едите там обходную ошибку, которую легко избежать. – user2357112

ответ

1

Это проходит не уверен, что это то, что вы хотите, хотя

@Test 
public void testRounding() { 

    // prove there is a value that displays cleanly 
    Double cleanValue = 0.6d; 
    assertEquals("0.6", cleanValue.toString()); 

    Double value = 0.6975265613d; 

    // get double value truncated to 1 decimal place 
    value = BigDecimal.valueOf(value).setScale(1,BigDecimal.ROUND_DOWN).doubleValue(); 

    // this fails with 0.6000000000000001 
    assertEquals("0.6", value.toString()); 

} 
+0

Спасибо за ответ, но, как я уже сказал, BigDecimal слишком медленный. Например: запуск моего первоначального преобразования занимает 17 мс для повторений 100 М, в то время как метод BigDecimal занимает 47 333 мс на моей машине ... так что это больше, чем штраф в 3000 раз, чем штраф в 100 раз. Просто не сработает. – tsquared

+0

@tsquared: Сколько времени требуется для маршалирования данных и записи их на диск или отправки по сети или что-то еще? – user2357112

+0

@tsquared: Кроме того, считаете ли вы, что вы предлагаете Jackson своим собственным сериализатором для парных? – user2357112

Смежные вопросы