2015-06-06 6 views
2

Почему у меня возникают разные результаты при печати z, как показано в следующем фрагменте кода?
Кажется, что компилятор разрезает вторую «печать» всех позиций после «2» ... Спасибо за помощь!Номера Java и плавающей запятой

double z = 1.0; 
z = z + 0.1; 
z = z + 0.1; 
System.out.print("z := "+z); 
System.out.print(" # z:= "+((0.1+0.1)+(1.0))); 

Выход:

z := 1.2000000000000002 # z:= 1.2 
+3

На самом деле, это не тот же самый код. Вы должны сравнить с 1.0 + 0.1 + 0.1. – ericbn

+0

Прочитайте [Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой] (http://download.oracle.com/docs/cd/E19422-01/819-3693/ncg_goldberg.html) – ericbn

ответ

1
double z = 1.0; 
z = z + 0.1; 
z = z + 0.1; 

Печать z отображает значение, отличное 1.2, потому что в результате добавления 1.0 к 0.1 дважды не могут быть точно представлены в double.

System.out.print(" # z:= "+((0.1+0.1)+(1.0))); 

Отпечатано # z:= 1.2, потому что " # z:= "+((0.1+0.1)+(1.0)) обрабатывается компилятором как постоянная строка и заменяется непосредственно на # z:= 1.2 в скомпилированном коде. Другими словами, это утверждение точно эквивалентно:

System.out.print(" # z:= 1.2"); 
+1

почему *** добавление 1,0 к 0,1 дважды невозможно представить точно в двойном. ***? – Lrrr

+0

@Lrrr из-за того, как значение с плавающей запятой хранится в двоичном формате? – Gosu

+0

@ Gosu проблема с этим ответом в том, что он не объяснил главный вопрос, главный вопрос - это именно та часть, которую я выделил! – Lrrr

2

Первый код делает 1.0 + 0.1 (промежуточный результат 1.1) + 0.1. Второй код 0.1 + 0.1 (промежуточный результат: 0.2) + 1.0. Из-за точности с плавающей запятой, которая не может точно представлять каждое число, вы получаете разные результаты.

double z = 1.0; 
z = z + 0.1; 
System.out.println(z); 
z = z + 0.1; 
System.out.println(z); 
z = 0.1; 
z = z + 0.1; 
System.out.println(z); 
z = z + 1.0; 
System.out.println(z); 

Выход:

1.1 
1.2000000000000002 
0.2 
1.2 

http://ideone.com/XGsRRj

Подробнее на http://floating-point-gui.de/

0

Используйте BigDecimal, чтобы получить точные результаты расчета. Бинарные форматы, такие как float и double, могут иметь лучшую производительность, но приводят к неожиданным результатам при преобразовании их в десятичные числа.

Некоторые цифры не могут быть точно представлены в двоичном формате. Мы все знаем эту проблему, когда пытаемся написать «третью» в десятичном представлении (0.33333 ... никогда не заканчивая).

Пример кода:

BigDecimal z = new BigDecimal("1.0"); 
z = z.add(new BigDecimal("0.1")); 
z = z.add(new BigDecimal("0.1")); 
System.out.print("z := "+z); 
System.out.print(" # z:= "+((0.1+0.1)+(1.0))); 

Выход:

z := 1.2 # z:= 1.2 

запустить код на сайте http://ideone.com/vTVIK7

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