Подтвердить что ты не робот

Изменение поведения для возможной потери точности

В Java, когда вы делаете

int b = 0;
b = b + 1.0;

Вы получаете возможную потерю точности. Но почему это, если вы делаете

int b = 0;
b += 1.0;

Нет ошибок?

4b9b3361

Ответ 1

Это потому, что b += 1.0; эквивалентно b = (int) ((b) + (1.0));. сужение примитивного преобразования (JLS 5.1.3) скрывается в составной операции присваивания.

JLS 15.26.2 Операторы присваивания соединений (JLS Third Edition):

Выражение составного присваивания формы E1 op = E2 эквивалентно E1 = (T) ((E1) op (E2)), где T - тип E1, за исключением того, что E1 оценивается только один раз.

Например, следующий код верен:

short x = 3;
x += 4.6;

и приводит к x, имеющему значение 7, потому что оно эквивалентно:

short x = 3;
x = (short)(x + 4.6);

Это также объясняет, почему компилируется следующий код:

byte b = 1;
int x = 5;
b += x; // compiles fine!

Но это не так:

byte b = 1;
int x = 5;
b = b + x; // DOESN'T COMPILE!

В этом случае необходимо явно указать:

byte b = 1;
int x = 5;
b = (byte) (b + x); // now it compiles fine!

Стоит отметить, что неявный листинг в сложных присваиваниях является предметом Головоломки 9: Tweedledum из замечательной книги Java Puzzlers. Вот несколько выдержек из книги (слегка отредактированных для краткости):

Многие программисты считают, что x += i; является просто сокращением для x = x + i;. Это не совсем так: если тип результата шире, чем у переменной, оператор составного присваивания выполняет молчащее сужение примитивного преобразования.

Чтобы избежать неприятных сюрпризов, не используют составные операторы присваивания для переменных типа byte, short или char. При использовании сложных операторов присваивания для переменных типа int убедитесь, что выражение в правой части не имеет типа long, float или double. При использовании сложных операторов присваивания для переменных типа float убедитесь, что выражение в правой части не имеет типа double. Эти правила достаточны, чтобы компилятор не создавал опасные сужающие приведения.

Для разработчиков языка, вероятно, ошибкой для сложных операторов присваивания создавать невидимые роли; составные назначения, где переменная имеет более узкий тип, чем результат вычисления, вероятно, должны быть незаконными.

Следует отметить последний абзац: С# гораздо более строг в этом отношении (см. Спецификация языка С# 7.13.2 Составное назначение).

Ответ 2

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

И последним он может преобразовывать 1.0 в integer вместо этого и делать целое дополнение?

Только предположение.