2015-03-27 5 views
4

Я работаю над пониманием ограничений двойного. 0,1 не может быть выражена в конечной системе, поскольку она является повторяющимся двоичным значением. Но, когда я объявляю переменную и даю ей 0,1, она по-прежнему печатает как 0,1 и не .0999999999999999, 1.000000000000001 или что-то подобное. Но, если я добавлю переменную, которая имеет 0,1 десять раз, она выйдет на .9999999999999999, что я и ожидал.Сравнение «0,1» с .1

Реальный вопрос, почему он печатает ровно в 0,1, когда я знаю, что это невозможно, и у меня есть доказательство, что это не истинное значение?

double d = 0.1; 
System.out.printf("%.16f\n",d); 
System.out.printf("%.16f", d + d + d + d + d + d + d + d + d + d); 

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

".5" == .5? Ожидаемый ответ: Да.

".1" == .1? Ожидаемый ответ: Нет

Сравнение Я пытаюсь это

number = new BigDecimal("0.1"); 
d = number.doubleValue(); 
if (number.compareTo(new BigDecimal(Double.toString(d))) == 0){ 
    // Doing something 
} 

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

+1

Вы уверены, что 'BigInteger' верен для вас? Кроме того, почему бы вам не напрямую поддерживать 'd' в конструкторе' BigDecimal'? – Clashsoft

+0

Вы правы, это должно было быть BigDecimal. Я только пытался получить соответствующие биты кода и сделал эту ошибку. Я исправил это в вопросе. –

ответ

4

Чтобы проверить, если String представляет собой double значение, которое вы можете сделать это:

private static boolean isADouble(String s) { 
    return new BigDecimal(s).equals(new BigDecimal(Double.parseDouble(s))); 
} 

public static void main(String[] args) { 
    System.out.println(isADouble("0.1")); // false 
    System.out.println(isADouble("0.5")); // true 
} 

Это работает, потому что new BigDecimal(s) производит BigDecimal точно равное значению, представленному String, в то время как new BigDecimal(Double.parseDouble(s)) является точным значением Ближайшиеdouble к этому значению.

Я объясню в конце почему number.compareTo(new BigDecimal(Double.toString(d))) == 0 делает не работа.

Когда вы

double d = 0.1; 
System.out.println(d); 

вы получите ответ 0.1, потому что d является ближайшим double к «реальным» 0.1. (double d = 0.1;средства «сделать d ближайший к double0.1». Когда вы пишете

System.out.println(d + d + d + d + d + d + d + d + d + d); 

вы видите 0.9999999999999999, а не 1. Причина вы не видите 1, потому что есть double значения ближе к единице, чем ответ (фактически один из них - это значение double). Нет причин, по которым ответ должен быть самым близким double к одному, потому что d на самом деле не был 0.1 (он был только рядом с ним), а в в любом случае, когда вы добавляете числа с плавающей запятой неточностями повторно введен.

Наконец, number.compareTo(new BigDecimal(Double.toString(d))) == 0 не работает, потому что даже number.doubleValue() является не точно 0.1, Double.toString() еще преобразует его в String"0.1" потому что нет double значения ближе «реальной» 0.1.

+0

* «Наконец, number.compareTo (новый BigDecimal (Double.toString (d))) == 0 не работает, потому что« * вы не можете сравнивать BigInteger с 'BigDecimal' :). Но вы можете быть правы, если OP будет читать ошибки компилятора и будет использовать 'number = new BigDecimal (« 0.1 »); вместо этого. – Tom

+0

@Tom Хороший улов. Я не заметил, что в вопросе упоминался «BigInteger». –

+0

Благодарим за помощь. Я случайно использовал BigInteger в начальном вопросе. Я отредактировал его. Спасибо вам за помощь. Я никогда не использовал Bigs раньше, и я пытаюсь их сбить. Я немного удивлен, что у них нет встроенных в них функций класса Math. –

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