ビット単位の補数演算子(〜チルド)はどのように機能しますか?


回答:


282

負の数は、正数の2の補数として格納されることに注意してください。例として、2の補数での-2の表現を次に示します(8ビット)。

1111 1110

これを取得する方法は、数値のバイナリ表現を取り、その補数を取り(すべてのビットを反転)、1を加えることです。2は0000 0010で始まり、ビットを反転させると1111 1101になります。1を追加すると上記の結果が得られます。最初のビットは符号ビットで、負を意味します。

では、〜2 = -3を取得する方法を見てみましょう。

再び2つあります。

0000 0010

すべてのビットを反転するだけで、次のことが得られます。

1111 1101

さて、2の補数で-3はどのように見えますか?正の3:0000 0011から始め、すべてのビットを1111 1100にフリップし、1を加算して負の値(-3)、1111 1101にします。

したがって、単にビットを2に反転すると、-3の2の補数表現が得られます。

補数演算子(〜)はビットを反転するだけです。これらのビットを解釈するのはマシン次第です。


43
もう1つ言及しておきたいのは、フリップを1の補数と呼ぶ前に1の補数と呼ぶことです
Chris S

3
それは、1の補数と2の補数を認識していない他の人を助けるかもしれません。それらについてはこちらをお読みください。 en.wikipedia.org/wiki/Ones%27_complement en.wikipedia.org/wiki/Two%27s_complement
Sai

1
それはビットごとのNOT演算子ではありませんか?
Braden Best

3
マシンは、より高い正の数ではなく2の補数の負の数を取得していることをどのようにして知るのでしょうか。型がsigned intとunsignedのどちらであるかを示すそれぞれの言語の型システムのせいですか?
GL2014

@ GL2014あなたはそこであなた自身の質問に答えたと思います。私の理解では、それはそもそも機械が動作するように設計された方法です。
geekidharsh

40

~ 値のビットを反転します。

なぜ、~2ある-3数字をビット単位の表現方法に関係していますが。数値は2の補数として表されます。

つまり、2はバイナリ値です

00000010

そして、〜2はビットを反転するので、値は次のようになります。

11111101

これは、-3のバイナリ表現です。


2
11111101 == 10進253対-3ではありませんか?
AKS

10
符号付き整数と符号なし整数のどちらを表すかによって異なります。
driis 2016

18

他の人が言及したよう~に、ビットを反転しただけで(1を0に、0を1に変更)、2の補数以降が使用されるため、見た結果が得られます。

追加することの1つは 2の補数が使用される理由です。これは、負の数の演算が正の数の演算と同じになるようにするためです。ゼロを取得するために追加する必要が-3ある数と考えて3ください。この数は1101であることがわかります。バイナリの加算は小学校(10進数)の加算と同じで、10ではなく2に到達したときに1を加算するだけです。 。

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

したがって、1101-3、取得するビットを00102つ反転させます。


8

この演算は補足であり、否定ではありません。

〜0 = -1と考え、そこから作業します。

否定のアルゴリズムは、「補数、増分」です。

知ってますか?逆数対称である「1の補数」もあり、0と-0の両方があります。


6

この質問の回答が長い間投稿されていることは知っていますが、同じ質問に対する回答を共有したいと思いました。

数値の1の補数を見つけるには、まずその2進数の等価物を見つけます。ここでは、10進数20000 0010バイナリ形式で表されます。次に、バイナリ表現のすべての桁を反転(すべての1を0に、すべての0を1に反転)することで、その1の補数を取得します。

0000 0010 → 1111 1101

これは、10進数2の1の補数です。また、最初のビット、つまり符号ビットは2進数で1であるため、格納されている数に対して符号がであることを意味します。(ここでは、言及された数 2ではなく、2の補数です)。

ここで、数値は2の補数として格納されるため(数値の1の補数に1を加えたもの)、この2進数1111 1101を10 進数に表示するには、最初に2の補数を見つける必要があります。

1111 1101 → 0000 0010 + 1 → 0000 0011

これは2の補数です。2進数の10進数表現0000 00113です。そして、上記のように符号ビットは1だったので、結果の答えは-3です。

ヒント:この手順を注意深く読んだ場合、1の補数演算子の結果は、実際には数値(この演算子が適用されるオペランド-)に負の符号が付いたものになります。他の番号でもこれを試すことができます。


なぜ2回追加するのですか?見てるよadd, flip, add0010-> 0011-> 1100->1101
Braden Best

1
フリップ、フリップ、追加です。1の補数の最初のフリップ。また、システムでは2の補数で保存されるため、数値を表示する必要がある場合は、保存されている数値の2の補数が表示されます(つまり、2番目のフリップと加算)。
Himanshu Aggarwal 2015年

しかし、flip(flip(2))はちょうど2ではありませんか?0010 1101 0010
Braden Best

はい、それは2つだけになります。しかし、ビットがメモリに格納されるとき、最上位ビットは1だったので、上記の回答で説明したように、後で数値が負になります。
Himanshu Aggarwal、2015年

1
あなたが説明していることと私が調査したすべてから、これは2の補数ではなく、「通常の」補数、またはビット単位のNOTです。論理的に、NOT 0 = 1そしてNOT 1 = 0。4ビットシステムでは、NOT 0011(3)= 1100(12符号なし、-4符号付き)。私の理解から、2の補数はと定義され(NOT n) + 1、ビット数に関係なく、数値の負の対応を見つけるために使用されます。したがって、2c(5) = -5。ほら、今、それは完全に理にかなっています。この操作をそれが何であるかを呼び出す限り、ビット単位のNOTです。
ブレーデンベスト

4

int a = 4; System.out.println(〜a); 結果は:-5

Javaの任意の整数の「〜」は、noの1の補数を表します。たとえば、私は〜4を取っています。これは、バイナリ表現0100を意味します。最初に、整数の長さは4バイトです。つまり、4 * 8(1バイトは8ビット)= 32です。したがって、システムメモリでは、4は0000 0000 0000 0000 0000 0000 0000 0100として表されます。ここで〜演算子は、上記のバイナリに対して1の補数を実行します

つまり、1111 1111 1111 1111 1111 1111 1111 1011-> 1の補数の最上位ビットは、1の場合はno(-または+)の符号を表し、0の場合は符号-、次に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 0000 0101これで結果は-5になります。ビデオのこのリンクを確認してください<[Javaのビット単位の演算子] https://youtu.be/w4pJ4cGWe9Y


2

単に...........

任意の数の2の補数として、1を追加するよりもすべて1を0に、またはその逆に反転することで計算できます。

ここで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ビットを補うために、通常は1である符号ビットとして格納されます。そして、結果は〜10 = -11になります。

〜(-11)= 10;

上記は、printf( "%d"、〜0);の場合に当てはまります。結果は-1です。

しかし、結果よりprintf( "%u"、〜0):32ビットマシンでは4294967295。


1

ビット単位の補数演算子(〜)は単項演算子です。

以下の方法で機能します

最初に、指定された10進数を対応するバイナリ値に 変換します.2の場合、最初に2を0000 0010に変換します(8ビットの2進数に)。

次に、数値のすべての1を0に、すべてのゼロを1に変換します。その後、数値は1111 1101になります。

これは、-3の2の補数表現です。

補数を使用して、つまり単に1111 1101を10進数(= 4294967293)に変換するために符号なしの値を見つけるには、印刷中に%uを使用するだけです。


1

ほとんどの人にとって混乱の部分は10進数と符号付き2進数の違いによるものだと思うので、まずそれを明確にしましょう。

人間の10進数の世界の場合:01は1を意味し、-01は-1を意味します。コンピューターのバイナリの世界の場合:101は、符号なしの場合は5を意味します。101は、符号付き数字が位置xにあるときに符号付きの場合、(-4 + 1)を意味します。| バツ

したがって、2の反転ビット=〜2 =〜(010)= 101 = -4 + 1 = -3混乱は、署名された結果(101 = -3)と署名されていない結果(101 = 5)の混合によるものです。


1

tl; dr ~はビットを反転します。その結果、サインが変わります。~2負の数(0b..101)です。負の数を出力するにはrubyprints -、次に2の補数~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。2つのドット(..)は、無数のを表し1ます。結果の最上位ビット(MSB)はであるため1、結果は負の数((~2).negative? == true)です。負の数の出力にrubyプリント-し、内部値の2の補数。2の補数は、ビットを反転してからを追加することによって計算され1ます。2の補数は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ように負の数を出力するのは、格納された値を絶対値の2の補数として扱うためです。つまり、保存されるのは0b..101です。これは負の数なので、ある値の2の補数ですx。を見つけるxには、の2の補数を使用し0b..101ます。これはの2の補数の2の補数です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。結果は負の数になります。2の補数は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_length0x0f.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進数に分割し、最後の2進数に追加することによって逆にする必要があります。この実行後、前の数字とは反対の符号を与えなければなりません〜2 = -3 :2sバイナリ形式は00000010から11111101への変更これは1の補数であり、次に00000010 + 1 = 00000011が補完されます。これは3のバイナリ形式であり、-sign Ie、-3


0

ビット単位の演算子は、私の経験と知識に従って、符号と大きさの方法で機能する単項演算子です。

たとえば、〜2は-3になります。

これは、MSBが符号ビットである場合、ビットごとの演算子は最初に0000 0010(8ビット演算子)である符号と大きさで数値を表すためです。

その後、2の負の数、つまり-2が使用されます。

-2は、符号と大きさで1000 0010(8ビット演算子)として表されます。

その後、LSBに1が追加され(1000 0010 + 1)、1000 0011になります。

-3です。


0

JavaScriptのチルダ(〜)は、指定された値を1の補数に変換します。すべてのビットが反転されます。 それがチルダのすべてです。意欲的なサインではありません。数量は加算も減算もされません。

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

JavaScriptのような高水準言語を使用する標準のデスクトッププロセッサでは、BASE10符号付き算術が最も一般的ですが、覚えておいてください。それが唯一の種類ではありません。CPUレベルのビットは、いくつかの要因に基づいて解釈されます。「コード」レベルでは、この場合は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 

上記のすべてが同時に当てはまります。


0

基本的に行動は否定ではなく補完です。

ここで、x =〜xは結果-(x + 1)を常に生成します。

x =〜2

-(2 + 1)

-3

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.