web-dev-qa-db-ja.com

0と-0を区別することは可能ですか?

整数値0-0は本質的に同じであることを知っています。しかし、私はそれらを区別することが可能かどうか疑問に思っています。

たとえば、変数に-0が割り当てられているかどうかを知るにはどうすればよいですか?

bool IsNegative(int num)
{
    // How ?
}

int num = -0;
int additinon = 5;

num += (IsNegative(num)) ? -addition : addition;

-0は、0とまったく同じ方法でメモリに保存されますか?

92
Filip Minx

対象のマシンによって異なります。

2の補数表現 を使用するマシンでは、整数にビットレベルで違いはありません0-0の間(それらは同じ表現を持ちます) )

マシンが 1の補数 を使用している場合、間違いなく

0000 0000   -> signed   0 
1111 1111   -> signed   −0

ネイティブサポートを使用することについて明らかに話しているので、x86シリーズプロセッサは、符号付き数値の2の補数表現をネイティブにサポートしています。他の表現を使用することは確かに可能ですが、おそらく効率が低下し、より多くの指示が必要になります。

(JerryCoffinが指摘したように:たとえ補数が主に歴史的な理由で考慮されたとしても、 符号付きの大きさの表現 はまだかなり一般的であり、負と正のゼロに対して別々の表現を持っています)

112
Marco A.

int(ほぼ普遍的な「2の補数」表現)の場合、0-0の表現は同じです。 (IEEE 754浮動小数点など、他の数値表現では異なる場合があります。)

14
RichieHindle

0を2の補数で表現することから始めましょう(もちろん、他にも多くのシステムと表現が存在します。ここでは、この特定のものを参照しています)。

0000 0000

次に、すべてのビットを反転し、1を追加して2の補数を取得します。

1111 1111 (flip)
0000 0001 (add one)
---------
0000 0000

0000 0000、それは-0の表現でもあります。

ただし、1の補数では、符号付き0は0000 0000ですが、-0は1111 1111です。

12
Maroun

CとC++の実装は通常密接に関連しているため、この答えは残しておくことにしましたが、実際には、思っていたようにC標準に従うことはありません。重要な点は、C++標準ではこのような場合に何が起こるかを指定していないということです。また、実世界では2の補数でない表現は非常にまれであり、たとえ存在する場合でも、多くの場合、誰かが簡単に発見できるものとして公開するのではなく、多くの場合に違いを隠します。


存在する整数表現での負のゼロの動作は、C標準のようにC++標準で厳密に定義されていません。ただし、C標準(ISO/IEC 9899:1999)をトップレベルの規範的な参照として引用しています[1.2]。

C規格[6.2.6.2]では、負のゼロは、ビット単位の演算、または負のゼロが既に存在する演算(負のゼロを値で乗算または除算したり、負のゼロをゼロ)-あなたの例のように、単項マイナス演算子を通常のゼロの値に適用すると、通常のゼロになることが保証されます。

canが負のゼロを生成する場合でも、負のゼロをサポートするシステムでさえ、それらが負になるという保証はありません。

これらのケースが実際に負のゼロを生成するのか、通常のゼロを生成するのか、および負のゼロがオブジェクトに格納されたときに通常のゼロになるのかは不明です。

したがって、次のように結論付けることができます。いいえ、このケースを検出する信頼できる方法はありません。 2の補数表現が現代のコンピューターシステムでは非常にまれであるという事実がなくても。

C++標準は、「負のゼロ」という用語には言及しておらず、許可されていることに注意[3.9.1 para 7]を除いて、符号付き絶対値と1の補数表現の詳細についてはほとんど議論していません。

9
Random832

マシンに-0+0の異なる表現がある場合、memcmpはそれらを区別できます。

パディングビットが存在する場合、ゼロ以外の値に対しても実際には複数の表現が存在する可能性があります。

8
Ben Voigt

C++言語仕様では、負のゼロなどのintはありません。

これら2つの単語が持つ唯一の意味は、単項演算子- に適用されます 0、ちょうど+ 5は単なる二項演算子+ に適用されます 3および5

明確な負のゼロが存在する場合、2つの補数(整数型の最も一般的な表現)は、C++実装では不十分な表現になります。2つの形式のゼロを表現する方法はありません。


対照的に、浮動小数点(IEEEに準拠)には、正のゼロと負のゼロが別々にあります。たとえば、それらを1で割ると、区別できます。正のゼロは正の無限大を生成します。負のゼロは負の無限大を生成します。


ただし、int 0(または任意のint、または他のタイプの値)のメモリ表現が異なる場合は、memcmpを使用して次のことを発見できます。

#include <string>

int main() {
    int a = ...
    int b = ...
    if (memcmp(&a, &b, sizeof(int))) {
        // a and b have different representations in memory
    }
}

もちろん、直接メモリ操作以外でこれが発生した場合でも、2つの値はまったく同じように機能します。

5
Paul Draper

単純化するために、視覚化が簡単になった。

タイプint(_ 32)は32ビットで保存されます。 32ビットは2 ^ 32 = 4294967296固有値を意味します。したがって:

unsigned intデータ範囲は0から4,294,967,295

負の値の場合、それがどのように保存されるかによります。万一に備えて

の場合1の補数値-0が存在します。

2
Margus