Bitshifting длинный в Java

Я уверен, что это легко для тех, кто видит это первым!

Почему в Java код вроде

   long one = 1 << 0;
   long thirty = 1 << 30;
   long thirtyOne = 1 << 31;
   long thirtyTwo = 1 << 32;

   System.out.println(one+" = "+Long.toBinaryString(1 << 0));
   System.out.println(thirty+" = "+Long.toBinaryString(1 << 30));
   System.out.println(thirtyOne+" = "+Long.toBinaryString(1 << 31));
   System.out.println(thirtyTwo+" = "+Long.toBinaryString(1 << 32));

Печать

1 = 1
1073741824 = 1000000000000000000000000000000
-2147483648 = 1111111111111111111111111111111110000000000000000000000000000000
1 = 1

Это не имеет смысла для меня. long - это 64-битное число, тогда как оно похоже на int в приведенном выше. Я знаю, что bithifted byte претерпевает продвижение int, но я не вижу, что происходит в этом случае.

Любые указатели на то, что происходит здесь, будут хорошими:)

спасибо

EDIT: спасибо за все ответы - я понял, что происходит, как только я нажал "отправить", но SO перешел в режим readonly, и я не смог удалить! Большое спасибо!

Ответ 1

Это потому, что 1 является литералом int, поэтому к целому числу применяется <<. Результат отбрасывается до long, но к тому времени это слишком поздно.

Если вы пишете 1L < 32 и т.д., Тогда все будет хорошо. L используется для обозначения литерала long.

Ответ 2

Прежде всего:

Спецификация языка Java пункт 15.19

Операторы сдвига

Если продвинутым типом левого операнда является int, только пять младших бит правого операнда используются как расстояние сдвига. Это как если бы правый операнд подвергался поразрядному логическому оператору И и (§15.22.1) с значением маски 0x1f (0b11111). Поэтому фактически используемое расстояние сдвига всегда находится в диапазоне от 0 до 31 включительно.

Если продвинутый тип левого операнда длинный, то используются только шесть младших бит правого операнда как расстояние сдвига. Это как если бы правый операнд подвергался поразрядному логическому оператору И и (§15.22.1) с значением маски 0x3f (0b111111). Поэтому фактически используемое расстояние сдвига всегда находится в диапазоне от 0 до 63 включительно.

Итак, почему он работает так, как будто вы меняете int вместо long s? Потому что вы меняете int s! Вместо этого попробуйте использовать литерал long:

long thirtyTwo = 1L << 32;

Ответ 3

Он действует как int, потому что вы меняете ints! Чтобы сдвинуть длинный, вы должны суффиксом всего вашего номера с помощью l.

long one = 1l << 0;
long thirty = 1l << 30;
long thirtyOne = 1l << 31;
long thirtyTwo = 1l << 32;

System.out.println(one+" = "+Long.toBinaryString(1l << 0));
System.out.println(thirty+" = "+Long.toBinaryString(1l << 30));
System.out.println(thirtyOne+" = "+Long.toBinaryString(1l << 31));
System.out.println(thirtyTwo+" = "+Long.toBinaryString(1l << 32));

Что дает следующий результат:

1 = 1
1073741824 = 1000000000000000000000000000000
2147483648 = 10000000000000000000000000000000
4294967296 = 100000000000000000000000000000000

Ответ 4

Ну, вы используете int литералы, которые ведут себя как ints. Вместо этого используйте длинный литерал (т.е. 1L):

System.out.println(1 << 31);
System.out.println(1L << 31);  // <--
-2147483648
2147483648

Если у вас есть выражение типа 1 << 31, он оценивает фиксированное значение независимо от того, к чему ему назначено, будь то int или long.

Ответ 5

Это связано с тем, что по умолчанию число 1 в строке long thirtyTwo = 1 << 32; равно int. Вы должны явно указать его как задолго до того, как вы выполните операцию переключения. Теперь происходит то, что вы выполняете сдвиг на int, который после этого сдвига выполняется с int до long.

   long one = 1l << 0;
   long thirty = 1l << 30;
   long thirtyOne = 1l << 31;
   long thirtyTwo = 1l << 32;

Ответ 6

Проблема заключается в том, что 1 является целым числом. Он будет преобразован в долгий срок после смены. Попробуйте

   long one = 1l << 0;
   long thirty = 1l << 30;
   long thirtyOne = 1l << 31;
   long thirtyTwo = 1l << 32;

Ответ 7

Литерал 1 - это int. Используйте 1L (L как долго) и повторите попытку.