Почему преобразование double в int не работает должным образом в Java? - PullRequest
1 голос
/ 05 октября 2019

Я начал читать документацию по Java8 и пробовал разные примеры кода. Ниже показано странное поведение.

Sample1

Double di = new Double(Math.pow(2,32-1));
System.out.printf("%f\n",di.doubleValue()); //2147483648.000000
int a= di.intValue();
System.out.println(a); //2147483647

Sample2

Double di = new Double(Math.pow(2,32-1)) - 1.0;
System.out.printf("%f\n",di.doubleValue()); //2147483647.000000
int a= di.intValue();
System.out.println(a); //2147483647

Как получается, что в обоих случаях значение int возвращает одно и то же значение?

Ответы [ 3 ]

1 голос
/ 05 октября 2019

См. https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3 Важная часть, выделенная жирным шрифтом в конце:

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

На первом шаге число с плавающей точкой преобразуется либо в длинное, если T длинное, либо в int, если T байтовое, короткое, char или int, следующим образом:

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

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

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

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

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

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

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

Сказав это, ваш double значение 2147483648 (вы можете попробовать с большим числом). Самое высокое представимое значение int int равно 2147483647. Вот почему в итоге вы получите 2147483647.

0 голосов
/ 05 октября 2019

Это связано с тем, что максимальное значение типа int в Java равно 2147483647. Когда вы вызываете Double::doubleValue, он выполнит сужающее преобразование, если значение, которое вы пытаетесь преобразовать, выходит за пределы и это указано в документах этого метода:

Возвращаетзначение этого Double как int после сужающего примитивного преобразования.

И оно даже указывает на JLS 5.1.3 , где описано это сужающее преобразование.

Для преобразования значений с плавающей запятой требуется два шага. Причина, по которой вы видите это значение, объясняется в предложении для первого шага, точка три, опция b:

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

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

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

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

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

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

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

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

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

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

  2. На втором шаге:

    • Если T - int или long, - результат tПреобразование является результатом первого шага.

    • Если T является байтом, символом или коротким, результат преобразования является результатом сужающегося преобразования в тип T(§5.1.3) результата первого шага.

Таким образом, результатом будет наибольшее представимое значение типа int,в этом случае.

0 голосов
/ 05 октября 2019

int значение не может превышать Integer.MAX_VALUE , что в точности равно 2147483647 . Вы добровольно отказываетесь от всех хвостов, когда вызываете intValue () .

...