Чому “$ ((~ 33))” дає -34?


12
$ echo $(( 255 ))
255
$ echo $(( 33 ))
33
$ echo $(( ~33 ))
-34
$ echo $(( ~255 ))
-256
$ 

і моє ядро:

$ uname -a
Linux HOSTNAME 3.2.0-40-generic-pae #64-Ubuntu SMP Mon Mar 25 21:44:41 UTC 2013 i686 i686 i386 GNU/Linux

ПИТАННЯ: ~ призначено для відмови від номера AFAIK. Але чому ~33виробляє -34і чому ~255виробляє -256?


2
Побітове заперечення, не плутати з арифметичним запереченням ( -x )
Чепнер

Відповіді:


21

Сторінка людини bash говорить:

   ! ~    logical and bitwise negation

Підписані номери, як правило, зберігаються у додатку Доповнення двох :

...
-4 = 1100
-3 = 1101
-2 = 1110
-1 = 1111
 0 = 0000
 1 = 0001
 2 = 0010
 3 = 0011
...

Це означає, що якщо ви берете число на зразок 2, воно розрядне інтерпретується як 0010. Після побітового заперечення це стає 1101, що представляє -3.


10

Це результат арифметики комплементу двох.

~є побітним запереченням, яке інвертує всі біти, якими управляє. Арифметика двох доповнення працює, перевернувши всі біти і додавши 1. Оскільки ви перевернули біти, але не додали жодного, ви отримуєте те саме число, перевернуте, мінус один.

У Вікіпедії є гарна стаття на доповнення до двох тут .

Як приклад:

  • 3 у двійковій є 0011
  • Бінарний показник -3 в (доповнення двох) 1101
  • Інвертування 0011дає вам 1100, що становить -4, оскільки ви не додали 1.

3

Оператор ~ є побітовим оператором НЕ. Використовувати його не те саме, що відкидати число.

З Вікіпедії , побітна операція NOT дорівнює значенню двох мінусів значення:

НЕ x = −x - 1

Відмова від двійкового числа еквівалентна прийняттю значення у двох доповненнях.

Використовуючи оператор ~ NOT = візьміть його значення одного доповнення.

Простіше кажучи, ~ просто гортає всі біти бінарного подання .

Для ваших прикладів:

33 (десятковий) = 0x00100001 (8-бітний двійковий)

~ 33 = ~ 0x00100001 = 0x11011110 = -34 (десятковий)

Або в десятковій арифметиці, використовуючи формулу ~ x = -x - 1:

~ 33 = -33 - 1 = -34

і

~ 255 = -255 - 1 = -256


1

Проблема полягає в тому, що ~ є оператором з розумом. Отже, ви заперечуєте більше бітів, ніж ви, можливо, плануєте. Ви можете побачити це краще, перетворивши результати в шістнадцятковий, наприклад:

result_in_hex=$(printf "%x" $(( ~33 ))); echo $result_in_hex
ffffffffffffffde

порівняно з тим, що у вас було:

result_in_dec=$(printf "%d" $(( ~33 ))); echo $result_in_dec
-34

Я припускаю, що ти маєш намір заперечувати 0x33. Якщо це так, то це діятиме:

result_in_hex=$(printf "%2x" $(( ( ~ 0x33 ) & 0xFF))); echo $result_in_hex
cc

Вам також потрібно використовувати & що є трохи розумним та оператором, щоб уникнути всіх ff на старті.


1

Оператор ~(арифметичний) перевертає всі біти , його називають оператором побітового заперечення:

! ~    logical and bitwise negation

Так, у місцях, де контекст є арифметичним, він змінює число з усіма бітами як нулі на всі біти як одиниці. A $(( ~0 ))перетворює всі біти представлення числа (зазвичай це 64 біти сьогодні) у всі.

$ printf '%x\n' "$(( ~0 ))"
ffffffffffffffff

Число з усіма інтерпретується як негативне число (перший біт 1) 1, або просто -1.

$ printf '%x\n' "-1"
ffffffffffffffff

$ echo "$(( ~0 ))"
-1

Те ж саме відбувається з усіма іншими номерами, наприклад: $(( ~1 ))гортає всі біти:

$ printf '%x\n' "$(( ~1 ))"
fffffffffffffffe

Або у двійковій формі: 1111111111111111111111111111111111111111111111111111111111111110

Що, інтерпретується як число у поданні двох:

$ echo "$(( ~1 ))"
-2

Загалом, математичне рівняння людини таке, що $(( ~n ))дорівнює$(( -n-1 ))

$ n=0    ; echo "$(( ~n )) $(( -n-1 ))"
-1 -1

$ n=1    ; echo "$(( ~n )) $(( -n-1 ))"
-2 -2

$ n=255  ; echo "$(( ~n )) $(( -n-1 ))"
-256 -256

І (ваше запитання):

$ n=33   ; echo "$(( ~n )) $(( -n-1 ))"
-34 -34

0

Спочатку ви повинні зрозуміти, що 33 - це 32 біт або 64 біт.

Для зручності я беру восьмибітове число (= 1 байт)

десяткова 33 - у восьми бітах: 00100001, перегортання бітів призводить до 11011110.

Оскільки біт високого порядку дорівнює 1, це від’ємне число.

Друкуючи від’ємне число, система друкує знак мінус, а потім робить додаток двох на від’ємне число.

Доповненням двох є: гортання бітів та додавання 1.

11011110 ==> 00100001 ==> додавання 1 ==> 00100010 результатів у десятковій 34 за знаком мінус.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.