2015-06-02 5 views
17
long m = 24 * 60 * 60 * 1000 * 1000; 

Вышеупомянутый код создает переполнение и не печатает правильный результат.Переполнение происходит с умножением

long m2 = 24L * 60 * 60 * 1000 * 1000; 
long m3 = 24 * 60 * 60 * 1000 * 1000L; 

Вышеуказанные 2 строки печатают правильный результат.

Мои вопросы являются-

  1. Имеет ли значение для компилятора, который я использую, m2 или m3?
  2. Как java начинает умножаться? Слева направо или справа налево? Вычисляет ли 24 * 60 сначала или 1000 * 1000?
+1

oops- long m2 = 24L * 60 * 60 * 1000 * 1000 * 1000 * 1000; Длинные m3 = 24 * 60 * 60 * 1000 * 1000 * 1000 * 1000L; m2 и m3 не дают одинакового результата при повторном пересчете более 1000 раз в 1000 раз. Поэтому кажется, что умножение происходит слева направо. – rents

+2

Правильно, используйте 'm2', поэтому каждое промежуточное умножение повышается до' long'. Умножение лево-ассоциативное, поэтому оно идет слева направо. – GriffeyDog

+0

Умножение ассоциативно, поэтому порядок не имеет значения. Однако он вычисляется слева направо в тех случаях, когда это имеет значение, например вызовы методов, которые возвращают число. –

ответ

16

Я бы использовал линию m2 вместо линии m3.

Java оценивает оператор умножения * от left to right, поэтому сначала оценивается 24 * 60.

Просто так получилось, что 24 * 60 * 60 * 1000 (один 1000) не переполнение, так что к тому времени, когда вы умножить на 1000L (второй 1000), продукт произведен в long перед тем умножения, так что переполнение не принимает место.

Но, как вы упомянули в своих комментариях, больше факторов может вызвать переполнение в типе данных int до умножения последнего номера long, что дает неправильный ответ. Лучше использовать литерал long для первого (самого левого) номера, как в m2, чтобы избежать переполнения с самого начала. В качестве альтернативы вы можете отличить первый литерал как long, например. (long) 24 * 60 * ....

19

В данном случае -

long m = 24 * 60 * 60 * 1000 * 1000; 

Право задания оценивается первым. Справа нет данных типа long. Все это int. Таким образом, JVM попытаются совместить результат в int, после чего произошло переполнение.

А во втором случае -

long m2 = 24L * 60 * 60 * 1000 * 1000; 
long m3 = 24 * 60 * 60 * 1000 * 1000L; 

Вот один операнд умножения long. Поэтому другие запрашиваются автоматически long. Результат пытается соответствовать long. Наконец, назначение выполняется с помощью m2 и m3.

И да ассоциативность умножения слева направо - означает, что первый операнд берется первым. И на основе этого факта я думаю, что в этом случае мы должны использовать -

long m2 = 24L * 60 * 60 * 1000 * 1000; 

это утверждение, так как в этом заявлении продвижение к long занятыми местами ранее, что снижает риск переполнения.

+0

«Сначала слева оценивается назначение». ... вы имели в виду право? – Mints97

+0

Есть еще опечатка во втором предложении :) – Ruslan

+0

@Ruslan, я думаю, что у меня проблема с левым правом :(. – Razib

6

Умножающие работы слева направо и int * int Производит int.Так

24 * 60 * 60 * 1000 * 1000 

такой же, как

(((24 * 60)* 60) * 1000) * 1000 

, который дает нам

(((1440)* 60) * 1000) * 1000 
(( 86400 ) * 1000) * 1000 
( 86400000  ) * 1000 

и, наконец, из-за целого переполнения (так как 86400000000 является слишком большим для целого числа, которое максимальное значение 2147483647) результат be

500654080 

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

В этом случае вы можете сделать это в начале, как вы это делали в случае m2: 24L * 60, который будет производить long1440L, который снова будет умножен на Int 60 производства новых long, и так далее, производя только long значения.

m3 дело здесь работает, потому что вы умножая 86400000 на 1000L, что означает, что вы избегаете целочисленное переполнение, так как результат будет long.

9

Since expressions are evaluated from left to right, предпочла бы ваше первое решение (m2 = ...).

Рассуждение: давайте рассмотрим несколько иной пример.

long l = Integer.MAX_VALUE * 2 * 2L; 

Это выражение будет вычисляться -4, поскольку только последнее умножение бросает первое выражение long (которое -2 в данный момент времени, поскольку оба операнда int). Если вы пишете

long l = Integer.MAX_VALUE * 2L * 2; 

вместо l будет содержать ожидаемое значение 8589934588 поскольку первое умножение дает результат типа long.

4

Умножим больше цифр, эта линия будет переполняться даже есть 1000L:

long m3 = 24 * 60 * 60 * 1000 * 1000 * 1000 * 1000L; 

Хотя это даст правильный результат:

long m3 = 24L * 60 * 60 * 1000 * 1000 * 1000 * 1000; 

Таким образом, мы уверены, что Java начать умножения слева вправо, и мы должны начать с Long слева, чтобы предотвратить переполнение.

2

Это потому что, когда мы используем длинный один операнд, все остальные операнды типа int получают запрос на long.

Выражение в java оценивается слева направо.

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