web-dev-qa-db-ja.com

符号付き整数と符号なし整数が両方とも偶数か両方とも奇数かどうかを調べる

_int m_と_unsigned int j_があり、両方が偶数であるか、両方が奇数であるかを判断したい。

過去に私が使用している

_if((int(j)+m)%2)
_

1つだけが奇数である場合をキャッチします。しかし、intへのキャストが、jの奇数/偶数を誤って変更することを心配しています。

これらのいずれかが問題に遭遇しますか?

_if(!(j%2)!=!(m%2))
if(bool(j%2)!=bool(j%2))
_

そんなこと知ってる

_if(j%2!=m%2)
_

mが負の場合、 'm%2'は_-1_を生成し、_j%2_の値に関係なく常にtrueに評価されるため、機能しません。

31
Johnathan Gross

%を使用しないでください。これはビットマスクを必要とする問題です:

bool same_parity = (i & 0x1) == (j & 0x1);

この式の結果は常に0または1になるため、これはiの符号に関係なく機能します。

64
Barry
if (1 & (i ^ j))
{
// Getting here if i is even and j is odd
// or if i is odd and j is even
}

^exclusive-orビットごとの演算子で、両方の数値の各ビットが同じ値であるかどうかをチェックします。たとえば、iのバイナリ表現が0101であり、j1100である場合、i ^ jは最初と最後のビットが異なり、中間ビットは同じであるため、1001と評価されます。

&andビットごとの演算子で、両方が1である場合、両方の数値の各ビットをチェックします。

各数値の最後のビットだけが偶数か奇数かを決定するため、i ^ jは両方が偶数か奇数の場合は...xxx0に評価され、そうでない場合は...xxx1xsは関係ありません。とにかく)。 1は実際には...0001であるため、ijが両方とも偶数または奇数の場合、1 & (i ^ j)0に評価され、そうでない場合は1に評価されます。

これは、符号なしの数値、2の補数、および符号と大きさの任意の組み合わせで機能しますが、正確に1が負の場合、まれな1の補数では機能しません。

56
SolutionMill

2つの整数を追加するとパリティが追加されるため、解決策は単純です。

if ( (j + m) % 2 )

符号なしラップアラウンドは、モジュロUINT_MAX+1これは偶数です。

このソリューションは、負の数値表現などの実装固有の詳細に依存しません。


脚注:他の多くの回答がビットシフト、ビット補数、XORなどの問題を複雑にするために決定されている理由を見つけるのに苦労しています。残念ながら、IMO単純なコードではなくトリッキーなコード。

20
M.M

_unsigned int_より大きい_INT_MAX_をintにキャストしても、適切な値が返されるとは限りません。結果は未定義です。

intを_unsigned int_にキャストすると、常に定義された動作になります-いくつかのkに対して_mod 2^k_を計算し、すべての正のintが_2^k_未満になるようにします。

_if((int(j)+m)%2)
_

あるべき

_if((j+unsigned(m))%2)
_

代わりに。

_if((j%2)==(unsigned(m)%2))
_

両方が同じパリティを持っているかどうかを確認する最も簡単な方法です。符号なしaka _mod 2^k_に移動するとパリティが維持され、符号なし_%2_でパリティが正しく返されます(負のパリティではありません)。

あまりスマートにならないでください

これらのいずれかが問題に遭遇しますか?

if(!(j%2)!=!(m%2))
if(bool(j%2)!=bool(j%2))

私が見る1つの問題は読みやすさです。他の誰か(またはあなたの将来の自己)に、それが何をすべきか、または実際に何をするかが明らかでないかもしれません。

余分な行を追加することで、より表現力豊かになります。

#include <cmath>

const bool fooIsEven = foo % 2 == 0;
const bool barIsEven = std::abs(bar) % 2 == 0;
if (fooIsEven == barIsEven)
{
  // ...
}

また、与えられた2つの整数型のパリティの比較を提供する適切な名前の関数の実装を検討してください。これにより、コードがクリーンアップされるだけでなく、繰り返しを繰り返すこともできなくなります。

編集:std :: absの呼び出しによってキャストを置き換えました

6
plats1