7

ほとんどの場合、符号付き整数の負の数を表すために 2 の補数が使用され、それが最良の方法であると言う多くの記事を読みましたが、

しかし、なぜか頭にこびりついたこの(下)が、その歴史を知らずにはいられない。

「signed int を使用する場合、先頭のビットを 1 として使用して、負の数を示します。」

オンラインと StakOverflow で、2 の補数が負の数を表す最良の方法であるという多くの投稿を読みました。しかし、私の質問は最善の方法についてではなく、歴史について、または「先行ビット」の概念がどこから生まれて消えたのかということです。

PS: また、それは私だけではなく、他の多くの人々もこれに混乱していました.

編集 - 1 私が言及したいわゆるリーディング 1 メソッドは、この投稿の例で説明されてい ます。

1 の MSB は負の数を意味することがわかりました。これは 2 の補数の性質によるものであり、特別なスキームではありません。

例えば。最初のビットがなければ、1011 が -5 を表すか +11 を表すかはわかりません。

jamesdlin, Oli Charlesworth, Mr Lister に感謝します.

Rant: 1011 は -3 に評価されると教えられたり (誤って) 考えさせられたりしたグループ/人々がたくさんいると思います。1 は - を表し、011 は 3 を表します。

「私の質問は何だったのか..」と尋ねる人々は、おそらく最初に学んだときから正しい 2 の補数の方法を教えられており、これらの間違った答えにさらされることはありませんでした。

4

5 に答える 5

4

符号付き整数の 2 の補数表現にはいくつかの利点があります。

ここでは 16 ビットと仮定します。

0 ~ 32,767 の範囲の負でない数値は、符号付きと符号なしの両方の型で同じ表現を持ちます。(2 の補数は、この機能を 1 の補数および符号と大きさと共有します。)

2 の補数は、ハードウェアに簡単に実装できます。多くの演算では、符号付きおよび符号なしの算術演算に同じ命令を使用できます (オーバーフローを無視してもかまわない場合)。たとえば、-1 は1111 1111 1111 1111、+ 1 は と表され0000 0000 0000 0001ます。上位ビットが符号ビットであることを無視してそれらを加算すると、数学的な結果は次のようになり1 0000 0000 0000 0000ます。下位 16 ビットを除くすべてを削除する0000 0000 0000 0000と、正しい符号付き結果である が得られます。同じ操作をunsigned65535 + 1と解釈すると、 が追加され、 が得られます。0これは正しい符号なしの結果です (ラップアラウンド モジュロ 65536 を使用)。

先行ビットは「符号ビット」ではなく、別の値ビットと考えることができます。符号なし2 進数表現では、各ビットは 0 または 1 に位の値を掛けた値を表し、合計値はこれらの積の合計です。最下位ビットの桁の値は 1、次の下位ビットは 2、次に 4 などです。16 ビットの符号なし表現では、上位ビットの桁の値は32768です。16 ビットの符号付き 2 の補数表現では、上位ビットの桁の値は-32768です。いくつかの例を試してみると、すべてうまくいくことがわかります。

詳細については、ウィキペディアを参照してください。

于 2012-05-03T06:19:23.690 に答える
2

先頭ビットだけではありません。それはすべてのビットについてです。

追加から開始

まず、2 + 7 の 4 ビット バイナリで加算がどのように行われるかを見てみましょう。

  10 + 
 111
____
1001

これは、10 進数での長い加算と同じです。ビットごと、右から左です。

  • 右端に 0 と 1 を足すと 1 になり、キャリーはありません。
  • 右から 2 番目に 1 と 1 を足すと、10 進数で 2、2 進数で 10 になります。0 を書き、1 を繰り上げます。
  • 右から 3 番目に、既にある 1 に運んだ 1 を追加すると、2 進数の 10 になります。0 を書き、1 を運びます。
  • 運ばれたばかりの 1 は、右から 4 番目に書き込まれます。

ロング減算

これで、2 進数の 10 + 111 = 1001 がわかったので、逆算して 1001 - 10 = 111 であることを証明できるはずです。

1001 -
  10
____
 111

これが私たちがしたことであり、再び右から左に作業しています:

  • 一番右の 1 - 0 = 1 に、それを書き留めます。
  • 2 番目に 0 - 1 があるので、余分なビットを借りる必要があります。ここでバイナリ 10 - 1 を実行すると、1 が残ります。これを書き留めます。
  • 3 番目に、余分なビットを借りたことを思い出してください。つまり、ここでも 0 - 1 です。同じトリックを使用して、余分なビットを借りて、10 - 1 = 1 を得て、結果の 3 番目に配置します。
  • 4 番目に、対処すべき借用ビットがあります。すでにある 1 から借りたビットを引きます: 1 - 1 = 0. 結果の前にこれを書き留めることができますが、それは引き算の終わりなので、その必要はありません。

ゼロ未満の数字がある!?

負の数についてどのように学んだか覚えていますか? アイデアの一部は、他の任意の数値から任意の数値を減算しても、数値を取得できるということです。したがって、7 - 5 は 2 です。6 - 5 は 1 です。5 - 5 は 0 です。4 - 5 とは何ですか? そのような数について推論する 1 つの方法は、単純に上記と同じ方法を適用して減算を行うことです。

例として、バイナリで 2 - 7 を試してみましょう:

     10 -
    111
_______
...1011

私は以前と同じ方法で始めました:

  • 一番右の場所で、0 から 1 を引きます。これには借用ビットが必要です。10 - 1 = 1 なので、結果の最後のビットは 1 です。
  • 右から 2 番目の場所では、1 - 1 に余分な借用ビットがあるため、さらに 1 を引く必要があります。これは、11 - 1 - 1 = 1 を与えるために、独自のビットを借用する必要があることを意味します。右から 2 番目のスポット。
  • 3位はトップナンバーにもうビットがありません!しかし、一番下の数字のビットがなくなった場合と同じように、前に 0 があるふりをすることができることはわかっています。したがって、2 番目からのボロー ビットにより、0 - 1 - 1 になります。また少し借りなきゃ!とにかく、10 - 1 - 1 = 0 で、右から 3 番目に書き留めます。
  • ここで、非常に興味深いことが起こりました。減算の両方のオペランドの桁数がなくなりましたが、まだボロー ビットを処理する必要があります。ま、これまで通りやっていきましょう。上部オペランドと下部オペランドのどちらにもビットがないため、0 - 0 になりますが、ボロー ビットがあるため、実際には 0 - 1 です。

    (また借りなきゃ! このまま借り続けたら、もうすぐ破産宣告しなきゃいけない。)

    とにかく、ビットを借りると、10 - 1 = 1 になり、右から 4 番目に書きます。

今、半分の心を持つ人は、牛が家に帰るまでビットを借り続けようとしていることを理解しようとしています。忘れていたら、2 か所前にそれらを使い果たしました。しかし、続けようとすると、次のようになります。

...00000010
...00000111
___________
...11111011
  • 5 番目に 0 - 0 - 1 を取得し、少し借りて 10 - 0 - 1 = 1 を取得します。
  • 6 番目に 0 - 0 - 1 を取得し、少し借りて 10 - 0 - 1 = 1 を取得します。
  • 7 番目に 0 - 0 - 1 を取得し、少し借りて 10 - 0 - 1 = 1 を取得します。

...そして、好きなだけ多くの場所で続けます。 ところで、-5 の 2 の補数バイナリ形式を導き出したところです。

好きな数値のペアに対してこれを試して、任意の負の数値の 2 の補数形式を生成できます。0 - 1 を実行しようとすると、-1 が として表される理由がわかります...11111111。また、すべての 2 の補数の負の数の最上位ビット (元の質問の「先行ビット」) が 1 である理由も理解できます。

実際には、コンピューターには負の数を格納するためのビットが無数にあるわけではないため、通常は 32 などのより適切な数の後に停止します。位置 33 の余分な借用ビットをどうするか ええ、私たちは静かにそれを無視し、誰も気付かないことを願っています. 新しい数値システムが機能しないことに気付いた人は、整数オーバーフローと呼びます。

最終的な注意事項

もちろん、これが番号システムを機能させる唯一の方法ではありません。結局のところ、私があなたに 5 ドル借りていたとしても、あなたと私との現在の残高が 999999995 ドルだったとは言えません。

しかし、導き出したばかりのシステムにはいくつかの優れた点があります。たとえば、このシステムでは、数値の 1 つが負であるという事実を無視しても、減算によって正しい結果が得られるという事実です。通常、条件付きステップで減算を考える必要があります: 2 - 7 を計算するには、まず 2 が 7 より小さいことを把握する必要があるため、代わりに 7 - 2 = 5 を計算してから、前にマイナス記号を付けます2 - 7 = -5 を取得します。しかし、2 の補数では、引き算を先に進めるだけで、どちらの数が大きいかは気にせず、正しい結果が自然に出てきます。また、他の人は、足し算がうまく機能し、掛け算もうまく機能すると述べています。

于 2012-05-03T08:15:32.370 に答える
1

つまり、先頭のビットは使用しません。たとえば、8 ビットの符号付き char では、

11111111

-1 を表します。先頭のビットをテストして、それが負の数かどうかを判断できます。

2 の補数を使用する理由はいくつかありますが、最初の最大の理由は利便性です。上記の数に 2 を足すと、結果はどうなるでしょうか?

00000001

2の補数の足し算・引き算は基本的に無料です。ロジックが非常に単純であるため、これは歴史的に大きな問題でした。署名付きの数値を処理するための専用ハードウェアは必要ありません。使用するトランジスタが少なく、複雑な設計が少なくて済むなどです。これは、乗算命令さえ組み込まれていない 8 ビット マイクロプロセッサの前にまでさかのぼります (多くの 16 ビットのものでさえ、それらを持っていませんでした。 65c816 (apple IIe およびスーパー NES で使用)。

そうは言っても、乗算は2の補数でも比較的簡単なので、大したことではありません。

于 2012-05-03T06:13:49.837 に答える
0

まあ、それ2 plus -2はゼロを与えるように働かなければなりませんでした。初期の CPU にはハードウェアの加算と減算があり、すべてのビット (1 の補数、元のシステム) を補数して値の「符号」を変更することで、既存の加算ハードウェアが適切に機能することに誰かが気付きました。マイナスゼロでした。(-0 と 0 の違いは何ですか? そのようなマシンでは、不確定でした。)

誰かがすぐに、2 の補数 (ビットを反転して 1 を追加することで数値を負と正の間で変換する) を使用することで、負のゼロの問題が回避されることに気付きました。

実際には、マイナスの影響を受けるのは符号ビットだけではなく、LSB を除くすべてのビットです。ただし、MSB を調べると、符号付きの値が負かどうかをすぐに判断できます。

于 2012-05-03T06:20:41.573 に答える