Как работает побитовый оператор дополнения (~ тильда)?

Ответы:

283

Помните, что отрицательные числа хранятся как дополнение двух положительного аналога. В качестве примера, вот представление -2 в дополнении к двум: (8 бит)

1111 1110

Чтобы получить это, нужно взять двоичное представление числа, взять его дополнение (инвертировать все биты) и добавить одно. Два начинается как 0000 0010, и инвертируя биты, мы получаем 1111 1101. При добавлении одного мы получим приведенный выше результат. Первый бит является знаковым битом, означающим отрицательный.

Итак, давайте посмотрим, как мы получим ~ 2 = -3:

Вот еще два:

0000 0010

Просто переверните все биты, и мы получим:

1111 1101

Ну, как выглядит -3 в дополнении к двум? Начните с положительного значения 3: 0000 0011, переверните все биты до 1111 1100 и добавьте один, чтобы получить отрицательное значение (-3), 1111 1101.

Так что, если вы просто инвертируете биты в 2, вы получите представление дополнения к -3.

Оператор дополнения (~) просто переворачивает биты. Это зависит от машины, чтобы интерпретировать эти биты.

Энтони
источник
44
Еще одна вещь, которую можно упомянуть, это то, что переворот называется дополнением 1 с, перед добавлением 1.
Крис С
3
Это может помочь другим, кто не знает о своем дополнении и дополнении двух. Читайте о них здесь. en.wikipedia.org/wiki/Ones%27_complement en.wikipedia.org/wiki/Two%27s_complement
Саи
1
Разве это не побитовый оператор НЕ?
Брэден Бест
3
Как машина узнает, что она получает отрицательное число из двух дополнений вместо более высокого положительного числа? Это из-за системы типов соответствующего языка, указывающей на то, что тип имеет тип int со знаком или без знака?
GL2014
@ GL2014 Я думаю, что вы ответили на свой вопрос там. В моем понимании, это то, как машина была разработана для работы в первую очередь.
geekidharsh
40

~ переворачивает биты в значении.

Почему ~2это -3связано с тем, как числа представляются поразрядно. Числа представлены как два дополнения .

Итак, 2 - это двоичное значение

00000010

И ~ 2 переворачивает биты, поэтому значение теперь:

11111101

Который является двоичным представлением -3.

driis
источник
2
Разве не 11111101 == десятичное 253 против -3?
AKS
10
Зависит от того, представляет ли оно целое число со знаком или без знака.
Дрис
Каково его использование в программировании реального мира? Есть ли у него приложения в конкурентном программировании?
Ноа Дж. Стэндерсон
18

Как уже упоминалось, ~только что перевернутые биты (меняются с одного на ноль и с нуля на один) и поскольку используется дополнение до двух, вы получите результат, который вы видели.

Одна вещь, которую нужно добавить, это то, почему используется дополнение до двух, так что операции с отрицательными числами будут такими же, как и с положительными числами. Подумайте о -3числе, к которому 3нужно прибавить, чтобы получить ноль, и вы увидите, что это число 1101, помните, что двоичное сложение похоже на сложение в начальной школе (десятичное), только вы несете единицу, когда вы получаете два, а не 10 ,

 1101 +
 0011 // 3
    =
10000
    =
 0000 // lose carry bit because integers have a constant number of bits.

Поэтому 1101это -3, флип биты , которые Вы получаете , 0010который является два.

Моти
источник
8

Эта операция является дополнением, а не отрицанием.

Считайте, что ~ 0 = -1, и работайте оттуда.

Алгоритм отрицания - «дополнение, приращение».

Вы знали? Существует также «поразрядное дополнение» , где обратные числа являются симметричными, и она имеет как 0 и -0.

gbarry
источник
6

Я знаю, что ответ на этот вопрос опубликован давно, но я хотел бы поделиться своим ответом на то же самое.

Чтобы найти дополнение к числу, сначала найдите его двоичный эквивалент. Здесь десятичное число 2представляется как 0000 0010в двоичной форме. Теперь, взяв свое дополнение, инвертируя (переворачивая все 1 в 0 и все 0 в 1) все цифры своего двоичного представления, что приведет к:

0000 0010 → 1111 1101

Это дополнение к десятичному числу 2. А поскольку первый бит, т. Е. Бит знака, равен 1 в двоичном числе, это означает, что знак является отрицательным для числа, которое он сохранил. (здесь упомянутое число не 2, а дополнение к 2).

Теперь, поскольку числа хранятся в виде дополнения к 2 (принимая дополнение к числу плюс один), поэтому для отображения этого двоичного числа 1111 1101в десятичном виде сначала нам нужно найти дополнение к его 2, которое будет:

1111 1101 → 0000 0010 + 1 → 0000 0011

Это дополнение 2-х. Десятичное представление двоичного числа 0000 0011, есть 3. И, поскольку бит знака был один, как упомянуто выше, итоговый ответ таков -3.

Подсказка: если вы внимательно прочитаете эту процедуру, то заметили бы, что результатом для оператора дополнения на самом деле является число (операнд - к которому применяется этот оператор) плюс единица со знаком минус. Вы можете попробовать это и с другими номерами.

Химаншу Аггарвал
источник
Почему это добавление в два раза? Я вижу add, flip, add. 0010-> 0011-> 1100->1101
Брэден Бест
1
Это флип, флип, добавить. Первый щелчок для дополнения 1. И поскольку он хранится в дополнении 2 в системе, когда вам нужно отобразить число, он покажет добавленное число 2 к сохраненному числу (т. Е. Второй щелчок и сложение).
Химаншу Аггарвал
Но разве не будет flip (flip (2)) просто 2? 0010 1101 0010
Брэден Бест
Да, это будет только 2. Но поскольку, когда биты хранятся в памяти, самый значимый бит был равен 1, что впоследствии сделает число отрицательным, как объяснено в ответе выше.
Химаншу Аггарвал
1
Судя по тому, что вы описываете, и всему, что я исследовал, это не дополнение к двум, а «обычное» дополнение или побитовое НЕТ. По логике NOT 0 = 1и NOT 1 = 0. В четырехбитной системе NOT 0011(3) = 1100(12 без знака, -4 со знаком). Из того, что я понимаю, дополнение к двум определяется как (NOT n) + 1и используется для поиска отрицательного аналога числа независимо от количества бит. Таким образом, 2c(5) = -5. Видите, теперь это имеет смысл. Пока вы называете эту операцию тем, чем она является: побитовым НЕ.
Брэден Бест
4

int a = 4; System.out.println (~ а); Результат будет: -5

'~' любого целого числа в java представляет собой 1 дополнение к no. например, я беру ~ 4, что означает в двоичном представлении 0100. во-первых, длина целого числа составляет четыре байта, то есть 4 * 8 (8 бит на 1 байт) = 32. Таким образом, в системной памяти 4 представлен как 0000 0000 0000 0000 0000 0000 0000 0100 теперь оператор ~ выполнит дополнение 1 к указанному выше двоичному номеру

то есть 1111 1111 1111 1111 1111 1111 1111 1011-> 1 дополняют наиболее значимый бит, представляющий знак «нет» (либо - или +), если он равен 1, то знак равен «-», если он равен 0, то знак равен «+» согласно этот наш результат - отрицательное число, в java отрицательные числа хранятся в форме дополнения 2, полученный результат мы должны преобразовать в дополнение 2 (сначала выполнить дополнение 1 и просто добавить дополнение 1 к 1). все единицы станут нулями, кроме старшего значащего бита 1 (который является нашим знаковым представлением числа, что означает оставшиеся 31 бит 1111 1111 1111 1111 1111 1111 1111 1011 (полученный результат оператора ~) 1000 0000 0000 0000 0000 0000 0000 0100 (1 дополнение)

1 (дополнение 2)

1000 0000 0000 0000 0000 0000 0101 теперь результат -5 проверить эту ссылку для видео <[Битовые операторы в Java] https://youtu.be/w4pJ4cGWe9Y

Майк Алудиав
источник
2

Просто ...........

Как 2-е дополнение любого числа мы можем вычислить, инвертируя все 1 с 0 и наоборот, чем мы добавляем 1 к нему.

Здесь N = ~ N дают результаты - (N + 1) всегда. Потому что система хранит данные в виде дополнения 2, что означает, что они хранят ~ N, как это.

  ~N = -(~(~N)+1) =-(N+1). 

Например::

  N = 10  = 1010
  Than ~N  = 0101
  so ~(~N) = 1010
  so ~(~N) +1 = 1011 

Теперь точка откуда минус. Мое мнение: предположим, что у нас есть 32-битный регистр, что означает 2 ^ 31 -1 бит, участвующий в работе, и оставшийся один бит, который изменяется в более ранних вычислениях (дополнении), сохраняется как знаковый бит, который обычно равен 1. И мы получаем результат как ~ 10 = -11.

~ (-11) = 10;

Вышесказанное верно, если printf ("% d", ~ 0); мы получаем результат: -1;

Но printf ("% u", ~ 0), чем результат: 4294967295 на 32-битной машине.

шубхам кумар мишра
источник
1

Побитовый оператор дополнения (~) является унарным оператором.

Это работает согласно следующим методам

Сначала он преобразует данное десятичное число в соответствующее ему двоичное значение. То есть в случае 2 он сначала преобразует 2 в 0000 0010 (в 8-битное двоичное число).

Затем он преобразует все 1 в числе в 0, а все нули в 1, тогда число станет 1111 1101.

это представление дополнения 2 -3.

Чтобы найти значение без знака с помощью дополнения, то есть просто преобразовать 1111 1101 в десятичное (= 4294967293), мы можем просто использовать% u во время печати.

james.bondu
источник
1

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

для десятичного мира человека: 01 означает 1, -01 означает -1, для двоичного мира компьютера: 101 означает 5, если он не подписан. 101 означает (-4 + 1), если подписано, в то время как цифра со знаком находится в позиции x. | Икс

таким образом, бит 2 перевернутый = ~ 2 = ~ (010) = 101 = -4 + 1 = -3 путаница возникает из-за смешивания подписанного результата (101 = -3) и неопределяемого результата (101 = 5)

user7537910
источник
1

TL; доктор ~ переворачивает биты. В результате знак меняется. ~2отрицательное число ( 0b..101). Для вывода отрицательного число rubyотпечатков -, то двоичное дополнение ~2: -(~~2 + 1) == -(2 + 1) == 3. Положительные числа выводятся как есть.

Там есть внутреннее значение и его строковое представление. Для натуральных чисел они в основном совпадают:

irb(main):001:0> '%i' % 2
=> "2"
irb(main):002:0> 2
=> 2

Последнее эквивалентно:

irb(main):003:0> 2.to_s
"2"

~переворачивает биты внутреннего значения. 2есть 0b010. ~2есть 0b..101. Две точки ( ..) представляют бесконечное число 1символов s. Поскольку старший значащий бит (MSB) результата равен 1, результатом является отрицательное число ( (~2).negative? == true). Для вывода отрицательного числа rubyпечатается -, а затем два дополняют внутреннее значение. Два дополнения рассчитывается путем переворачивания битов, а затем сложения 1. Два дополнения 0b..101есть 3. В качестве таких:

irb(main):005:0> '%b' % 2
=> "10"
irb(main):006:0> '%b' % ~2
=> "..101"
irb(main):007:0> ~2
=> -3

Подводя итог, он переворачивает биты, что меняет знак. Для вывода отрицательного числа он печатает -, затем ~~2 + 1( ~~2 == 2).

Причина, по которой rubyвыводит отрицательные числа примерно так, заключается в том, что он обрабатывает сохраненное значение как дополнение к абсолютному значению. Другими словами, то , что хранится в 0b..101. Это отрицательное число, и как таковое, это дополнение к некоторому значению x. Чтобы найти x, он делает два дополнения 0b..101. Который является дополнением двух до двух x. Который есть x(например ~(~2 + 1) + 1 == 2).

Если вы применяете ~отрицательное число, оно просто переворачивает биты (что, тем не менее, меняет знак):

irb(main):008:0> '%b' % -3
=> "..101"
irb(main):009:0> '%b' % ~-3
=> "10"
irb(main):010:0> ~-3
=> 2

Что более запутанно, так это ~0xffffff00 != 0xff(или любое другое значение с MSB, равным 1). Давайте немного упростим это ~0xf0 != 0x0f. Это потому, что это относится 0xf0к положительному числу. Что на самом деле имеет смысл. Так, ~0xf0 == 0x..f0f. Результатом является отрицательное число. Два дополнения 0x..f0fесть 0xf1. Так:

irb(main):011:0> '%x' % ~0xf0
=> "..f0f"
irb(main):012:0> (~0xf0).to_s(16)
=> "-f1"

Если вы не собираетесь применять побитовые операторы к результату, вы можете рассматривать их ~как -x - 1оператор:

irb(main):018:0> -2 - 1
=> -3
irb(main):019:0> --3 - 1
=> 2

Но это, возможно, не очень полезно.

Пример Предположим, у вас есть 8-битная (для простоты) сетевая маска, и вы хотите вычислить число 0единиц. Вы можете вычислить их, щелкая битами и вызывая bit_length( 0x0f.bit_length == 4). Но ~0xf0 == 0x..f0fмы должны отрезать ненужные биты:

irb(main):014:0> '%x' % (~0xf0 & 0xff)
=> "f"
irb(main):015:0> (~0xf0 & 0xff).bit_length
=> 4

Или вы можете использовать оператор XOR ( ^):

irb(main):016:0> i = 0xf0
irb(main):017:0> '%x' % i ^ ((1 << i.bit_length) - 1)
=> "f"
х-юри
источник
0

Сначала мы должны разделить данную цифру на двоичные цифры, а затем повернуть ее, добавив последнюю двоичную цифру. После этого выполнения мы должны поставить знак противоположный предыдущей цифре, которую мы находим завершенной ~ 2 = -3 Объяснение : 2s двоичная форма - 00000010, изменения - 11111101, это дополнение к ним, затем дополненное 00000010 + 1 = 00000011, что является двоичной формой из трех и с -sign Ie, -3

balusabavath
источник
0

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

Например, ~ 2 приведет к -3.

Это связано с тем, что побитовый оператор сначала должен представлять число в знаке и амплитуде, равное 0000 0010 (8-битный оператор), где MSB является знаковым битом.

Затем позже будет принято отрицательное число 2, которое равно -2.

-2 представляется как 1000 0010 (8-битный оператор) по знаку и величине.

Позже он добавляет 1 к LSB (1000 0010 + 1), что дает вам 1000 0011.

Который -3.

Сантош Кумар Джадав
источник
0

Javascript тильда (~) приводит данное значение к своему дополнению - все биты инвертированы. Это все, что делает тильда. Это не знак самоуверенного. Это не добавляет и не вычитает любое количество.

0 -> 1
1 -> 0
...in every bit position [0...integer nbr of bits - 1]

На стандартных процессорах для настольных компьютеров, использующих языки высокого уровня, такие как JavaScript, арифметика со знаком BASE10 является наиболее распространенной, но имейте в виду, что она не единственная. Биты на уровне ЦП подлежат интерпретации на основе ряда факторов. На уровне «кода», в данном случае JavaScript, они по определению интерпретируются как 32-разрядное целое число со знаком (давайте оставим поплавки вне этого). Думайте об этом как о кванте, эти 32 бита представляют множество возможных значений одновременно. Это полностью зависит от конвертирующего объектива, через который вы их просматриваете.

JavaScript Tilde operation (1's complement)

BASE2 lens
~0001 -> 1110  - end result of ~ bitwise operation

BASE10 Signed lens (typical JS implementation)
~1  -> -2 

BASE10 Unsigned lens 
~1  -> 14 

Все вышесказанное является верным одновременно.

Elvn
источник
0

В основном, действие - это дополнение, а не отрицание.

Здесь x = ~ x дают результаты - (x + 1) всегда.

х = ~ 2

- (2 + 1)

-3

Сунил
источник