Java: прямое присвоение слишком большого значения по сравнению с целочисленным переносом - PullRequest
1 голос
/ 08 марта 2020

Я изучал, как Java имеет дело с целочисленным переполнением и недостаточным заполнением, и я столкнулся с этими двумя ситуациями:

Если значение вне диапазона присваивается int напрямую, не может быть никакого переноса и это зависит от конверсии:

    long tooBigLong=2147483648L;
    int integerL=(int)tooBigLong;

    double tooBigDouble=Math.pow(2, 31);
    int integerD=(int)tooBigDouble;

результаты:

Converted from Long to int: -2147483648

Converted from Double to int: 2147483647

Кажется, что целочисленный переход будет происходят только когда я конвертирую из Long в int.

Но я хочу выяснить, как это не сработает для преобразования типа double в int? Спасибо за помощь!

1 Ответ

1 голос
/ 08 марта 2020

JLS определяет правила для 5.1.3. Сужающее примитивное преобразование :

При приведении long к int:

Сужающее преобразование целого числа со знаком в целочисленный тип T просто отбрасывает все, кроме n биты младшего разряда, где n - это число битов, используемых для представления типа T. В дополнение к возможной потере информации о величине значения цифр c, это может привести к тому, что знак полученного значения будет отличаться от знака входного значения.

Следовательно, отбрасывание старших 32 бит оригинальной длины и сохранение младших 32 бит приводит к отрицательному int в вашем примере.

При приведении double к int:

Сужающее преобразование числа с плавающей запятой в целочисленный тип T выполняется в два этапа:

  1. На первом этапе плавающее число точек преобразуется либо в long, если T long, либо в int, если T байтовое, короткое, char или int, следующим образом:

    • Если плавающий номер точки равен NaN (§4.2.3), результатом первого шага преобразования является int или long 0.

    • В противном случае, если число с плавающей запятой не является На бесконечности значение с плавающей запятой округляется до целочисленного значения V с округлением до нуля с использованием режима округления до нуля IEEE 754 (§4.2.3). Тогда есть два случая:

      a. Если T длинное, и это целочисленное значение может быть представлено как длинное, то результатом первого шага является длинное значение V.

      b. В противном случае, если это целочисленное значение может быть представлено как int, результатом первого шага будет значение int V.

    • В противном случае один из следующих двух случаев должен быть истинным:

      а. Значение должно быть слишком маленьким (отрицательное значение большой величины или отрицательная бесконечность), и результатом первого шага является наименьшее представимое значение типа int или long.

      b. Значение должно быть слишком большим (положительное значение большой величины или положительная бесконечность), а результатом первого шага является наибольшее представимое значение типа int или long.

Подсвеченная часть определяет, что (int)tooBigDouble должно привести к Integer.MAX_VALUE. Вы получите тот же результат для более высоких значений double. Например, для double tooBigDouble=Math.pow(2, 39);

...