Почему побитовый сдвиг влево в Python и C# имеет разные значения?Побитовый сдвиг влево в Python и C#
Python:
>>> 2466250752<<1
4932501504L
C#:
System.Console.Write((2466250752 << 1).ToString()); // output is 637534208
Почему побитовый сдвиг влево в Python и C# имеет разные значения?Побитовый сдвиг влево в Python и C#
Python:
>>> 2466250752<<1
4932501504L
C#:
System.Console.Write((2466250752 << 1).ToString()); // output is 637534208
Python гарантирует, что ваши целые числа не переполняются, а C# допускает переполнение (но генерирует исключение при переполнении в проверенном контексте). На практике это означает, что вы можете рассматривать целые числа Python как имеющие бесконечную ширину, а C# int
или uint
всегда 4 байта.
Обратите внимание, что в примере на Python значение «4932501504L» имеет конечный L, что означает длинное целое число. Python автоматически выполняет математику в длинной (размер доступной-памяти-ширины, в отличие от C# long
, которая составляет 8 байтов) целых чисел, когда переполнение происходит в значениях int. Вы можете увидеть обоснование этой идеи в PEP 237.
EDIT: Чтобы получить результат Python на C#, вы не можете использовать простой int
или long
- эти типы имеют ограниченный размер. Один тип, размер которого ограничен только памятью, - BigInteger. Он будет медленнее, чем int
или long
для арифметики, поэтому я бы не рекомендовал его использовать в каждом приложении, но это может пригодиться.
В качестве примера, можно написать практически один и тот же код, как и в C#, с тем же результатом, как и в Python:
Console.WriteLine(new BigInteger(2466250752) << 1);
// output is 4932501504
Это работает для произвольных размеров сдвига.Например, вы можете написать
Console.WriteLine(new BigInteger(2466250752) << 1000);
// output is 26426089082476043843620786304598663584184261590451906619194221930186703343408641580508146166393907795104656740341094823575842096015719243506448572304002696283531880333455226335616426281383175835559603193956495848019208150304342043576665227249501603863012525070634185841272245152956518296810797380454760948170752
Конечно, это переполнило бы долго.
Спасибо, но как я могу получить на Python результат как на C#? – user2160982
@ user2160982 См. Edit –
+1 для 'BigInteger' –
Вы переполнены 32-бит (без знака) целое число в C#.
В python все целые числа произвольного размера. Это означает, что целое число будет расширяться до любого размера. Обратите внимание, что я добавил подчеркивание:
>>> a = 2466250752
>>>
>>> hex(a)
'0x9300_0000L'
>>>
>>> hex(a << 1)
'0x1_2600_0000L'
^-------------- Note the additional place
В C#, uint
только 32 бита. Когда вы сдвигаете влево, вы превышаете размер целого числа, вызывая переполнение.
Перед сдвигая:
После сдвига:
Обратите внимание, что a
не имеет ведущего 1
, что питон показал.
Чтобы обойти это ограничение, в этом случае, вы можете использовать ulong
, который составляет 64 бит вместо 32 бит. Это будет работать для значений до 2 -1.
+1 для 'когда ты дерьмо левый'. Отличное объяснение тоже –
@SnakesandCoffee Ha, oops. Исправлена. –
Если вам нужно аналогичное поведение в C#, вам нужно будет использовать BigInteger (для любой длины) или Long (для этого случая) – Martheen
Мне нужно подобное поведение в Python :) – user2160982
О, просто И значение сразу после смещения вправо с 2^32-1 – Martheen