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

StackOverflow https://stackoverflow.com/questions/2696812

Вопрос

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

int b = 0;
b = b + 1.0;

Вы получаете возможную потерю прецизионной ошибки. Но почему, если вы сделаете

int b = 0;
b += 1.0;

Там нет никакой ошибки?

Это было полезно?

Решение

Это потому что 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)), куда Т это тип 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!

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top