480

私はコンピューター システムのコースにいて、部分的に2 の補数に苦労しています。私はそれを理解したいと思っていますが、私が読んだすべてが私のために絵をまとめていません. ウィキペディアの記事や、テキストブックを含む他のさまざまな記事を読みました。

したがって、このコミュニティ wiki投稿を開始して、2 の補数とは何か、それを使用する方法、およびキャスト (符号付きから符号なしへ、またはその逆)、ビットごとの操作、ビットシフト操作などの操作中に数値にどのように影響するかを定義したいと思いました。 .

私が望んでいるのは、プログラマーが簡単に理解できる明確で簡潔な定義です。

4

24 に答える 24

685

2 の補数は整数を格納する賢い方法であるため、一般的な数学の問題を非常に簡単に実装できます。

理解するには、バイナリの数値を考える必要があります。

それは基本的に言う、

  • ゼロの場合は、すべて 0 を使用します。
  • 正の整数の場合、最大 2 (ビット数 - 1) -1 でカウントアップを開始します。
  • 負の整数の場合もまったく同じことを行いますが、0 と 1 の役割を入れ替えてカウントダウンします (つまり、0000 で開始する代わりに、1111 で開始します。これが「補数」の部分です)。

4 ビットのミニバイトで試してみましょう (これをニブルと呼びます- 1/2 バイト)。

  • 0000- ゼロ
  • 0001- 1
  • 0010- 2
  • 0011- 三
  • 01000111- 4 から 7

それは私たちが前向きになれる限りです。2 3 -1 = 7.

ネガの場合:

  • 1111- 負のもの
  • 1110- マイナス 2
  • 1101- マイナス 3
  • 11001000- 負の 4 から負の 8

1000負の値 ( = -8) には、正の値では得られない追加の値が 1 つあることに注意してください。これは、0000がゼロに使用されるためです。これは、コンピュータの数直線と見なすことができます。

正の数と負の数の区別

これを行うと、最初のビットが「符号」ビットの役割を果たします。これは、負でない 10 進値と負の 10 進値を区別するために使用できるためです。最上位ビットが1の場合、2 進数は負であると言えます。一方、最上位ビット (左端) が0である場合、10 進値は非負であると言えます。

「符号の大きさ」の負の数は、対応する正の数の符号ビットが反転されているだけですが、このアプローチでは、混乱を招く「負のゼロ」として解釈する必要があります1000(1の1後にすべての s が続きます)。0

「1 の補数」の負の数は、対応する正の数の単なるビット補数であり、1111(すべて 1) との混乱を招く「負のゼロ」にもつながります。

ハードウェアのすぐ近くで作業していない限り、1 の補数または符号 - 大きさの整数表現を扱う必要はないでしょう。

于 2009-06-26T15:29:23.207 に答える
369

ウィキペディアの記事よりもうまく説明できないかと思います。

2 の補数表現で解決しようとしている基本的な問題は、負の整数を格納する問題です。

まず、4 ビットで格納された符号なし整数を考えます。あなたは次のものを持つことができます

0000 = 0
0001 = 1
0010 = 2
...
1111 = 15

これらは、負か正かを示すものがないため、符号なしです。

符号の大きさと超過表記

負の数を格納するには、さまざまなことを試すことができます。まず、最初のビットを符号ビットとして割り当てて +/- を表し、残りのビットをマグニチュードを表す符号マグニチュード表記を使用できます。したがって、再び 4 ビットを使用し、1 が - を意味し、0 が + を意味すると仮定すると、次のようになります。

0000 = +0
0001 = +1
0010 = +2
...
1000 = -0
1001 = -1
1111 = -7

それで、そこに問題があると思いますか?正の 0 と負の 0 があります。より大きな問題は、2 進数の足し算と引き算です。符号の大きさを使用して加算および減算する回路は非常に複雑になります。

とは

0010
1001 +
----

?

もう一つのシステムは過剰表記です。負の数を格納でき、2 つのゼロの問題を取り除くことができますが、足し算と引き算は難しいままです。

したがって、2 の補数が付属します。これで、正と負の整数を格納し、比較的簡単に演算を実行できます。数値を 2 の補数に変換する方法はいくつかあります。これが1つです。

10 進数を 2 の補数に変換する

  1. 数値を 2 進数に変換します (ここでは符号を無視します)。たとえば、5 は 0101、-5 は 0101 です。

  2. 数値が正の数値の場合は、完了です。たとえば、5 は 2 の補数表記を使用した 2 進数で 0101 です。

  3. 数値が負の場合

    3.1 補数を見つける (0 と 1 を逆にする) たとえば、-5 は 0101 なので、補数を見つけると 1010 になります

    3.2 補数 1010 + 1 = 1011 に 1 を加算します。したがって、2 の補数の -5 は 1011 です。

では、バイナリで 2 + (-3) を実行したい場合はどうなるでしょうか? 2 + (-3) は -1 です。これらの数値を加算するために符号の大きさを使用していた場合、何をしなければなりませんか? 0010 + 1101 = ?

2 の補数を使用すると、それがいかに簡単かを検討してください。

 2  =  0010
 -3 =  1101 +
 -------------
 -1 =  1111

2 の補数を 10 進数に変換する

1111 を 10 進数に変換する:

  1. 数字は 1 から始まるので負なので、1111 の補数である 0000 を見つけます。

  2. 0000 に 1 を足すと 0001 になります。

  3. 0001 を 10 進数に変換すると、1 になります。

  4. 記号 = -1 を適用します。

多田!

于 2009-06-26T15:48:38.563 に答える
135

私が見たほとんどの説明と同様に、上記の説明は 2 の補数を扱う方法については明確ですが、それら数学的に何であるかを実際に説明していません。少なくとも整数についてはそうしようと思います。最初に、おそらくよく知られているいくつかの背景について説明します。

10 進数の仕組みを思い出してください:
  2345は 2 × 10 3 + 3 × 10 2 + 4 × 10 1 + 5 × 10 0
の書き方です。
  

同様に、2 進数は、同じ一般的な考え方に従って01だけを使用して数値を記述する方法ですが、上記の 10 を 2 に置き換えます。次に、バイナリでは、
  1111は1 × 2 3 + 1 × 2 2 + 1 × 2 1 + 1 × 2 0
の書き方であり、計算すると 15 (基数 10) になります。  8+4+2+1=15だからです。
  

これはすべてうまくいき、正の数には適しています。人間が10進数で行うように、負の数の前にマイナス記号を付けるだけでも構わない場合は、負の数でも機能します。それはコンピュータでも可能ですが、私は 1970 年代初頭以来、そのようなコンピュータを見たことがありません。別の議論のために理由を残しておきます。

コンピューターの場合、負の数の補数表現を使用する方が効率的であることが判明しました。そして、ここで見落とされがちなことがあります。補数表記には、通常の正の数の前にある暗黙のゼロであっても、数の数字のある種の反転が含まれます。疑問が生じるので、それは厄介です:それらすべてですか?それは考慮すべき無限の桁数になる可能性があります。

幸いなことに、コンピューターは無限を表していません。数値は特定の長さ (または必要に応じて幅) に制限されます。それでは、正の 2 進数に戻りましょう。ただし、特定のサイズがあります。これらの例では、8 桁 (「ビット」) を使用します。したがって、2 進数は実際には
  00001111
または
  0 × 2 7 + 0 × 2 6 + 0 × 2 5 + 0 × 2 4 + 1 × 2 3 + 1 × 2 2 + 1 × 2 1 + 1 × 2 0になります。

2 の補数の負を形成するには、まずすべての (2 進) 数字を補数して 11110000 を形成
  
、1 を加えて
  11110001
を形成しますが、これが -15 を意味することをどのように理解すればよいでしょうか?

答えは、上位ビット (一番左のビット) の意味を変更することです。このビットは、すべての負の数に対して1になります。変更は、それが現れる数値の値への寄与の符号を変更することです。したがって、11110001
は、   - 1 × 2 7 + 1 × 2 6 + 1 × 2 5 + 1 × 2 4 +を表すと理解されます。 0 × 2 3 + 0 × 2 2 + 0 × 2 1 + 1 × 2 0
その式の前に「-」があることに注意してください。これは、符号ビットが重み -2 7、つまり -128 (基数 10) を持つことを意味します。他のすべての位置は、符号なし 2 進数の場合と同じ重みを保持します。

-15 を計算すると、
  -128 + 64 + 32 + 16 + 1
になります。電卓で試してみてください。-15です。

コンピューターで負の数を表現する 3 つの主な方法のうち、2 の補数は、一般的な使用の利便性から圧倒されます。しかし、それは奇妙さを持っています。バイナリなので、可能なビットの組み合わせは偶数でなければなりません。それぞれの正の数はその負の数と組み合わせることができますが、ゼロは 1 つしかありません。ゼロを否定するとゼロになります。したがって、もう 1 つの組み合わせがあります。符号ビットが1で、それ以外はすべて0の数値です。対応する正の数は、使用されているビット数に収まりません。

この数のさらに奇妙な点は、1 を補ったり足したりして正の数を作ろうとすると、同じ負の数が返されることです。ゼロがこれを行うのは当然のようですが、これは予期せぬことであり、私たちが慣れ親しんでいる動作とはまったく異なります。コンピューターは別として、私たちは通常、この固定長の算術演算ではなく、無制限の桁数の供給を考えているからです。

これは奇妙なことの氷山の一角のようなものです。水面下にはさらに多くの待ち伏せがありますが、この議論にはそれで十分です。固定小数点演算の「オーバーフロー」を調べれば、おそらくもっと見つかるでしょう。本当にやりたいのなら、「モジュラー算術」についても調べてみてください。

于 2012-08-18T20:39:49.260 に答える
16

有限数のビット/トリット/桁/何でもあると想像してください。0 はすべての桁が 0 であると定義し、自然に上向きにカウントします。

00
01
02
..

最終的にはオーバーフローします。

98
99
00

数字は 2 桁で、0 から 100 までのすべての数字を表すことができます。これらの数字はすべて正です。負の数も表現したいとしましょう。

私たちが実際に持っているのはサイクルです。2 の前の数字は 1 です。1 の前の数字は 0 です。0 の前の数字は… 99です。

簡単にするために、50 を超える数値はすべて負であるとしましょう。"0" から "49" は 0 から 49 を表します。"99" は -1、"98" は -2、... "50" は -50 です。

この表現は10 の補数です。通常、コンピュータは2 の補数を使用します。これは、数字の代わりにビットを使用することを除いて同じです。

10 の補数の良いところは、足し算だけが機能することです。正の数と負の数を加算するために特別なことをする必要はありません!

于 2009-06-26T19:04:18.720 に答える
5

2 の補数は、与えられた数の 1 の補数に 1 を加えることによって求められます。10101の 2 の補数を見つけてから、その 1 の補数を見つけなければならないとしましょう。つまり、この結果に01010足すと、最終的な答えになります。101010+1=01011

于 2010-09-13T13:59:14.800 に答える
4

答え 10 – 12 を 8 ビットを使用して 2 進形式で取得しましょう: 実際に行うのは 10 + (-12) です。

10 から 12 を引くには、12 の補数部分を取得する必要があります。バイナリの 12 は 00001100 です。バイナリの 10 は 00001010 です。

12 の補数部分を取得するには、すべてのビットを反転してから 1 を加算します。12 を 2 進数で反転すると 11110011 になります。これは逆コード (1 の補数) でもあります。1 つ追加する必要がありますが、これは現在 11110100 です。

つまり、11110100 は 12 の補数です。このように考えると簡単です。

これで、上記の 10 - 12 の問題をバイナリ形式で解くことができます。

00001010
11110100
-----------------
11111110  
于 2013-08-28T19:23:12.037 に答える
3

これまでの回答の多くは、2 の補数が負の数を表すために使用される理由をうまく説明していますが、2 の補数が何であるか、特に '1' が追加される理由はわかりません。実際、しばしば間違った方法で追加されます。

この混乱は、補数の定義がよく理解されていないことに起因します。補完とは、何かを完全にする欠落部分です。

基数 b の n 桁の数 x の基数補数は、定義により、b^nx です。2 進法では 4 は 100 で表され、3 桁 (n=3) で基数は 2 (b=2) です。したがって、基数補数は b^nx = 2^3-4=8-4=4 (または 2 進数で 100) です。

ただし、バイナリで基数の補数を取得することは、(b^n-1)-y として定義される減少基数補数を取得するほど簡単ではなく、基数補数より 1 だけ少なくなります。減数基数の補数を取得するには、すべての数字を反転するだけです。

100 -> 011 (減数 (1 の) 基数の補数)

基数 (2 の補数) を取得するには、定義で定義されているように、単純に 1 を加算します。

011 +1 ->100 (2 の補数)。

さて、この新しい理解で、Vincent Ramdhanie によって与えられた例を見てみましょう (上記の 2 番目の応答を参照)。

/* ヴィンセントの開始

1111 を 10 進数に変換する:

数字は 1 で始まるので負なので、1111 の補数を求めます。これは 0000 です。0000 に 1 を加えると、0001 が得られます。0001 を 10 進数に変換すると、1 になります。符号 = -1 を適用します。多田!

ヴィンセントの終わり */

と理解すべき

数字は 1 から始まるので、マイナスです。したがって、ある値 x の 2 の補数であることがわかります。2 の補数で表される x を見つけるには、まず 1 の補数を見つける必要があります。

x の 2 の補数: 1111 x の 1 の補数: 1111-1 ->1110; x = 0001, (すべての桁を反転)

記号 - を適用し、答え =-x =-1 を適用します。

于 2016-10-14T19:06:13.523 に答える
3

数学の観点から 2 の補数システムを見ると、それは本当に理にかなっています。10 の補数では、アイデアは本質的に違いを「分離」することです。

例: 63 - 24 = ×

24 の補数を追加しますが、これは実際には (100 - 24) です。つまり、方程式の両辺に 100 を足すだけです。

方程式は次のようになります: 100 + 63 - 24 = x + 100。これが、100 (または 10 または 1000 など) を削除する理由です。

ゼロの長い連鎖から 1 つの数値を引かなければならないという不便な状況のため、10 進法では 9 の補数である「減数基数補数」システムを使用します。

9 の大きな連鎖から差し引かれた数が表示されたら、数を逆にするだけで済みます。

例: 99999 - 03275 = 96724

それが理由で、9 の補数の後に 1 を足します。おそらく子供の頃の数学からわかるように、9 は 1 を「盗む」ことによって 10 になります。

バイナリでは、2 の補数は 10 の補数と同等であり、1 の補数は 9 の補数と同等です。主な違いは、差を 10 の累乗で分離しようとする (方程式に 10、100 などを追加する) 代わりに、2 の累乗で差を分離しようとしていることです。

このため、ビットを反転します。被減数が 10 進数の 9 の連鎖であるのと同様に、2 進数の被減数は 1 の連鎖です。

例: 111111 - 101001 = 010110

1 の連鎖は 2 のべき乗よりも 1 小さいため、10 進数で 9 が行うように、差から 1 を「盗みます」。

負の 2 進数を使用しているときは、実際には次のように言っています。

0000 - 0101 = ×

1111 - 0101 = 1010

1111 + 0000 - 0101 = x + 1111

x を「分離」するには、1111 は 10000 から 1 離れているため、1 を追加する必要があります。先頭の 1 は元の差に追加したばかりなので削除します。

1111 + 1 + 0000 - 0101 = x + 1111 + 1

10000 + 0000 - 0101 = x + 10000

両辺から 10000 を取り除くだけで x が得られます。これは基本的な代数です。

于 2015-08-26T03:50:54.410 に答える
3

補完という言葉は完全性に由来します。10 進数の世界では、0 ~ 9 の数字は、すべての 10 進数を表すために、数字または数字記号の補数(完全なセット) を提供します。2 進数の世界では、数字 0 と 1 はすべての 2 進数を表現するために数字の補数を提供します。実際には、正 (0) と負 (1) だけでなく、すべて (テキスト、画像など) を表すために記号 0 と 1 を使用する必要があります。私たちの世界では、数値の左側の空白はゼロと見なされます。

                  35=035=000000035.

コンピュータの保管場所には空白スペースはありません。すべてのビット (2 進数) は 0 または 1 のいずれかでなければなりません。メモリ番号を効率的に使用するために、8 ビット、16 ビット、32 ビット、64 ビット、128 ビットの表現として格納できます。8 ビットの数値として格納されている数値が 16 ビットの場所に転送される場合、符号と大きさ (絶対値) は同じままでなければなりません。1 の補数表現と 2 の補数表現の両方がこれを容易にします。名詞として: 1 の補数と 2 の補数は両方とも、最上位ビット (左側のビット) が符号ビットである符号量のバイナリ表現です。0 はプラス、1 はマイナスです。 2の補数は負を意味しない. 署名された数量を意味します。10 進数と同様に、マグニチュードは正の量として表されます。構造体は、より多くのビットを持つレジスタ [] にプロモートするときに、符号拡張を使用して数量を保持します。

       [0101]=[00101]=[00000000000101]=5 (base 10)
       [1011]=[11011]=[11111111111011]=-5(base 10)

動詞として: 2 の補数はを否定することを意味します。ネガティブにするという意味ではありません。これは、マイナスがプラスになることを意味します。正の場合は負にします。大きさは絶対値です:

        if a >= 0 then |a| = a
        if a < 0 then |a| = -a = 2scomplement of a

この機能により、否定してから加算することを使用した効率的なバイナリ減算が可能になります。a - b = a + (-b)

1 の補数を取る公式の方法は、各桁の値を 1 から減算することです。

        1'scomp(0101) = 1010.

これは、各ビットを個別に反転または反転することと同じです。これはあまり愛されていない負のゼロになるため、te 1 の補数に 1 を追加すると問題が解消されます。2 の補数を否定または取得するには、まず 1 の補数を取得してから 1 を追加します。

        Example 1                             Example 2
         0101  --original number              1101
         1's comp  1010                       0010
         add 1     0001                       0001
         2's comp  1011  --negated number     0011

例では、否定は符号拡張された数値でも機能します。

加算:
1110 キャリー 111110 キャリー 0110 は 000110 と同じ 1111 111111 sum 0101 sum 000101

減算:

    1110  Carry                      00000   Carry
     0110          is the same as     00110
    -0111                            +11001
  ----------                        ----------
sum  0101                       sum   11111

2 の補数を使用する場合、数値の左側の空白は正の数値の場合は 0 で埋められますが、負の数値の場合は 1 で埋められます。桁上げは常に加算され、1 または 0 のいずれかでなければなりません。

乾杯

于 2019-04-13T23:21:57.573 に答える
2

2 の補数: 数値の 1 の補数に 1 を追加すると、2 の補数が得られます。例: 100101 の 1 の補数は 011010 で、2 の補数は 011010+1 = 011011 (1 の補数に 1 を追加することにより)詳細については、 この記事でグラフで説明しています。

于 2014-11-26T09:29:03.227 に答える
2

私はラビニオの答えが好きでしたが、ビットをシフトすると複雑さが増します。多くの場合、符号ビットを尊重しながらビットを移動するか、符号ビットを尊重せずにビットを移動するかを選択できます。これは、数値を符号付き (ニブルの場合は -8 から 7、バイトの場合は -128 から 127) として扱うか、全範囲の符号なし数値 (ニブルの場合は 0 から 15、バイトの場合は 0 から 255) として扱うかの選択です。

于 2009-06-26T15:49:10.530 に答える
2

これは、データ型のビットの組み合わせの約半分が負の整数用に予約され、対応する正の整数に負の整数のほとんどを加算するとキャリー オーバーフローが発生するように、負の整数をエンコードする巧妙な手段です。結果はバイナリ ゼロになります。

したがって、2 の補数では、1 が 0x0001 の場合、-1 は 0x1111 になります。これは、合計が 0x0000 (1 のオーバーフロー) になるためです。

于 2012-06-20T09:10:41.073 に答える
0

数値のビット単位の補数とは、その中のすべてのビットを反転することです。2 の補数にするために、すべてのビットを反転して 1 を追加します。

符号付き整数の 2 の補数表現を使用して、2 の補数演算を適用して、正の数をその負の等価物に、またはその逆に変換します。したがって、例としてニブルを使用すると、0001(1) は1111(-1) になり、op を再度適用すると、 に戻ります0001

ゼロでの操作の動作は、正のゼロと負のゼロを特別に処理することなく、ゼロの単一表現を与えるという利点があります。に 1 を加えたものです00001111にオーバーフローし0000、正と負の 1 ではなく 1 つのゼロが得られます。

この表現の主な利点は、符号なし整数の標準加算回路を適用すると正しい結果が得られることです。たとえば、 nibbles: に 1 と -1 を追加すると0001 + 1111、ビットがレジスタからオーバーフローし、 が残り0000ます。

穏やかな紹介として、すばらしいコンピューターマニアがこの件に関するビデオを作成しました。

于 2019-02-15T20:42:45.293 に答える
0

問題は「2の補数」とは?それを理論的に理解したい人のための簡単な答え (そして私は他のより実用的な答えを補完しようとしています): 2 の補数は、+ や - などの追加の文字を必要としない双対系の負の整数の表現です。

于 2021-05-09T03:09:31.710 に答える
0

参照: https://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html

すべてのビットを反転して 1 を追加します。

  // in C++11
  int _powers[] = {
      1,
      2,
      4,
      8,
      16,
      32,
      64,
      128
  };

  int value=3;
  int n_bits=4;
  int twos_complement = (value ^ ( _powers[n_bits]-1)) + 1;
于 2016-12-30T18:31:29.293 に答える
-2

オンライン計算機を使用して、10 進数の 2 の補数バイナリ表現を計算することもできます: http://www.convertforfree.com/twos-complement-calculator/

于 2016-09-22T00:33:42.240 に答える
-6

最も簡単な答え:

1111 + 1 = (1)0000。したがって、1111 は -1 でなければなりません。次に、-1 + 1 = 0 です。

これらすべてを理解するのは完璧です。

于 2015-09-25T17:31:01.820 に答える