web-dev-qa-db-ja.com

なぜ(18446744073709551615 == -1)が本当ですか?

string::npos何かに気付いたが、ウェブ上でその説明を見つけることができなかった。

(string::npos == ULONG_MAX)

そして

(string::npos == -1)

本当です。

だから私はこれを試しました:

(18446744073709551615 == -1)

これも事実です。

どうしてそれが可能ですか?バイナリ会話が原因ですか?

12
Bahadır

18,446,744,073,709,551,615

記載されているこの番号18,446,744,073,709,551,615は、実際には2^64 − 1です。ここで重要なことは、2^64-1は本質的に0ベースの2^64です。符号なし整数の最初の桁は、0ではなく、1です。したがって、最大値が1の場合、2つの可能な値があります:0、または1(2)。

すべてのビットがオンになっている64ビットバイナリの2^64 - 1を見てみましょう。

1111111111111111111111111111111111111111111111111111111111111111b

-1

64ビットバイナリの+1を見てみましょう。

0000000000000000000000000000000000000000000000000000000000000001b

One's Compliment(OCP)で負にするには、ビットを反転します。

1111111111111111111111111111111111111111111111111111111111111110b

コンピューターはほとんどOCPを使用せず、Two's Compliment(TCP)を使用します。 TCPを取得するには、OCPに追加します。

1111111111111111111111111111111111111111111111111111111111111110b (-1 in OCP)
+                                                              1b (1)
-----------------------------------------------------------------
1111111111111111111111111111111111111111111111111111111111111111b (-1 in TCP)

「しかし、待って」と尋ねます。TwosCompliment -1が、

1111111111111111111111111111111111111111111111111111111111111111b

そして、バイナリ2^64 - 1

1111111111111111111111111111111111111111111111111111111111111111b

それから彼らは平等です!そして、それはあなたが見ているものです。符号付き64ビット整数と符号なし64ビット整数を比較しています。 C++では、コンパイラは署名された値を符号なしの値に変換します。

更新

技術的な修正 コメントのdavmacに感謝 の場合、signedである-1から同じサイズのunsigned型への変換が実際に指定されています言語であり、アーキテクチャの機能ではありません。以上のことから、上記の答えは、2つの賛辞をサポートしているが、信頼できる結果を保証する仕様に欠けているArch /言語を理解するのに役立つかもしれません。

10
Evan Carroll

string::nposconstexpr static std::string::size_type string::npos = -1;として定義されます(または、クラス定義内でconstexpr static size_type npos = -1;になるが、それは本当に無関係です)。

符号なしの型に変換される負の数値のラップアラウンド(std::string::size_typeは基本的にstd::size_t、これは符号なし)は、規格によって完全に明確に定義されています。 -1は、符号なし型の表現可能な最大値にラップします。これは、あなたの場合は18446744073709551615です。 std::size_tのサイズは実装定義であるため、正確な値は実装定義であることに注意してください(ただし、問題のシステムで可能な最大の配列のサイズを保持できます)。

8
rubenvb

C++標準(ドキュメント番号:N3337またはドキュメント番号:N4296)によれば、std::string::nposは次のように定義されます

static const size_type npos = -1;

ここで、std :: string :: size_typeは、符号なし整数型です。したがって、std :: string :: nposが-1に等しいという素晴らしいことはありません。初期化子はstd::string::nposのタイプに変換されます。

この方程式は

(string::npos == ULONG_MAX) is true,

それは、型std::string::nposが使用される実装unsigned longに型を持つことを意味します。この型は通常、size_t型に対応しています。

この方程式では

(18446744073709551615 == -1)

左のリテラルには、そのような大きなリテラルを格納するのに適した符号なし整数型があります。したがって、符号ビットを伝搬することにより、右オペランドもこの符号なしの型に変換されます。左のオペランドはそれ自体が型の最大値を表すため、それらは等しくなります。

1

これはすべて、符号付きオーバーフローと、負の数が2の補数として格納されるという事実です。つまり、負の数の絶対値を取得するには、すべてのビットを反転させて1を追加します。 8ビットの比較を行うときの意味255と-1は同じバイナリ値11111111を持ちます。同じことがより大きな整数にも当てはまります

https://en.m.wikipedia.org/wiki/Two%27s_complement

0
doron