符号付き整数と符号なし整数の違いは次のとおりです。
- 符号なしは、より大きな正の値を保持でき、負の値は保持できません。
- 符号なしでは、先頭ビットを値の一部として使用しますが、符号付きバージョンでは、左端のビットを使用して、数値が正か負かを識別します。
- 符号付き整数は、正数と負数の両方を保持できます。
他に違いはありますか?
符号付き整数と符号なし整数の違いは次のとおりです。
他に違いはありますか?
回答:
符号なしは、より大きな正の値を保持でき、負の値は保持できません。
はい。
符号なしでは、先頭ビットを値の一部として使用しますが、符号付きバージョンでは、左端のビットを使用して、数値が正か負かを識別します。
符号付き整数を表す方法はいくつかあります。視覚化する最も簡単な方法は、左端のビットをフラグ(符号と大きさ)として使用することですが、より一般的なのは2の補数です。どちらも最近のほとんどのマイクロプロセッサで使用されています。浮動小数点は符号と大きさを使用し、整数演算は2の補数を使用します。
符号付き整数は、正数と負数の両方を保持できます。
はい
x86のハードウェアレベルの違いについて説明します。コンパイラーを作成している場合やアセンブリー言語を使用している場合を除き、これはほとんど関係ありません。しかし、知っておくと便利です。
まず、x86は、符号付き数値の2の補数表現をネイティブでサポートしています。他の表現を使用することもできますが、これにはより多くの命令が必要になり、一般にプロセッサ時間の無駄になります。
「ネイティブサポート」とはどういう意味ですか?基本的には、符号なしの数値に使用する一連の命令と、符号付きの数値に使用する一連の命令があることを意味します。符号なしの数値は、符号付きの数値と同じレジスタに格納でき、実際にプロセッサを気にすることなく、符号付きと符号なしの命令を混在させることができます。数値が署名されているかどうかを追跡し、適切な指示を使用するのはコンパイラ(またはアセンブリプログラマ)の責任です。
まず、2の補数には、加算と減算が符号なしの数値とまったく同じであるという特性があります。数値が正でも負でも違いはありません。(あなただけ先に行くと、そうADD
とSUB
心配することなく、あなたの数字。)
比較に関しては、違いが明らかになり始めています。x86にはそれらを区別する簡単な方法があります。上/下は符号なしの比較を示し、大きい/小さいは符号付きの比較を示します。(たとえばJAE
、「以上の場合はジャンプ」を意味し、符号なしです。)
また、符号付き整数と符号なし整数を処理するための乗算と除算の2つのセットがあります。
最後に、オーバーフローなどをチェックする場合は、符号付きの数値と符号なしの数値で異なる方法でチェックします。
完全性のためのほんのいくつかのポイント:
この答えは整数表現のみを説明しています。浮動小数点には他の答えがあるかもしれません。
負の数の表現は異なる場合があります。今日使用される最も一般的な(はるかに-今日ではほぼ普遍的です)は、2の補数です。他の表現には、1の補数(かなりまれ)と符号付きの大きさ(ほとんどありませんが、おそらく博物館の作品でのみ使用されます)が含まれます。
2の補数を使用する場合、変数は正数よりも負数の範囲を(1だけ)大きく表現できます。これは、正の数にはゼロが含まれているため(符号ビットがゼロに設定されていないため)、負の数は含まれていないためです。つまり、最小の負の数の絶対値を表すことができません。
1の補数または符号付きの大きさを使用する場合、正または負の数としてゼロを表すことができます(これは、これらの表現が通常使用されない2つの理由の1つです)。
ポイント2を除くすべてが正しいです。符号付き整数にはさまざまな表記法があり、最初の実装を使用する実装もあれば、最後の実装を使用する実装もあれば、まったく異なるものを使用する実装もあります。それはすべて、使用しているプラットフォームによって異なります。
他の人が言ったことに加えて、Cでは、符号なし整数をオーバーフローさせることはできません。動作は、モジュラス算術であると定義されています。符号付き整数をオーバーフローさせることができます。理論的には(現在の主流システムでは実際には行われていませんが)、オーバーフローによって障害が発生する可能性があります(おそらくゼロ除算障害に似ています)。
(2番目の質問への回答)符号ビットのみを使用して(2の補数ではなく)、最終的に-0にすることができます。あまりきれいではありません。
Cの符号付き整数は数値を表します。a
およびb
が符号付き整数型の変数である場合、標準では、コンパイラが式をそれぞれの値の算術合計以外のものにa+=b
格納することを要求しませんa
。確かに、算術合計がに収まらない場合、a
プロセッサはそこに置くことができない可能性がありますが、標準では、コンパイラが値を切り捨てたりラップしたりする必要はありません。それらのタイプの制限。標準では必要ありませんが、Cの実装では、算術オーバーフローを符号付きの値でトラップできます。
Cの符号なし整数は、2のべき乗を法として合同である整数の抽象代数環として動作します。ただし、より大きな型への変換や操作を伴うシナリオを除きます。任意のサイズの整数を32ビット符号なし型に変換すると、その整数mod 4,294,967,296に一致するものに対応するメンバーが生成されます。2から3を引くと、4,294,967,295になります。これは、3に一致するものを4,294,967,295に一致するものに追加すると、2に一致するものになるためです。
抽象代数リング型は、多くの場合便利です。残念ながら、Cは型がリングとして動作するかどうかの決定要因として符号付きを使用します。さらに悪いことに、符号なしの値は、より大きな型に変換されるとリングメンバーではなく数値として扱われ、数値よりも小さい符号なしの値int
は、算術が実行されると数値に変換されます。場合v
でuint32_t
等しい4,294,967,294
、その後v*=v;
にする必要がありますv=4
。残念ながら、int
が64ビットの場合、何v*=v;
ができるかわかりません。
標準のままで、代数環に関連する動作が必要な場合は符号なしの型を使用し、数値を表現する場合は符号付きの型を使用することをお勧めします。Cが区別をその方法で描いたのは残念ですが、それは彼らがそうであるものです。
符号なし整数は、符号付き整数よりも特定の罠に捕まる可能性がはるかに高いです。トラップは、上記の1と3は正しいが、どちらのタイプの整数にも、「保持」できる範囲外の値を割り当てることができ、暗黙のうちに変換されるという事実から来ています。
unsigned int ui = -1;
signed int si = -1;
if (ui < 0) {
printf("unsigned < 0\n");
}
if (si < 0) {
printf("signed < 0\n");
}
if (ui == si) {
printf("%d == %d\n", ui, si);
printf("%ud == %ud\n", ui, si);
}
これを実行すると、両方の値が-1に割り当てられ、宣言が異なっていても、次の出力が得られます。
signed < 0
-1 == -1
4294967295d == 4294967295d