_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
に評価されるため、機能しません。
%
を使用しないでください。これはビットマスクを必要とする問題です:
bool same_parity = (i & 0x1) == (j & 0x1);
この式の結果は常に0
または1
になるため、これはi
の符号に関係なく機能します。
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
であり、j
が1100
である場合、i ^ j
は最初と最後のビットが異なり、中間ビットは同じであるため、1001
と評価されます。
&
はand
ビットごとの演算子で、両方が1
である場合、両方の数値の各ビットをチェックします。
各数値の最後のビットだけが偶数か奇数かを決定するため、i ^ j
は両方が偶数か奇数の場合は...xxx0
に評価され、そうでない場合は...xxx1
(x
sは関係ありません。とにかく)。 1
は実際には...0001
であるため、i
とj
が両方とも偶数または奇数の場合、1 & (i ^ j)
は0
に評価され、そうでない場合は1
に評価されます。
これは、符号なしの数値、2の補数、および符号と大きさの任意の組み合わせで機能しますが、正確に1が負の場合、まれな1の補数では機能しません。
2つの整数を追加するとパリティが追加されるため、解決策は単純です。
if ( (j + m) % 2 )
符号なしラップアラウンドは、モジュロUINT_MAX+1
これは偶数です。
このソリューションは、負の数値表現などの実装固有の詳細に依存しません。
脚注:他の多くの回答がビットシフト、ビット補数、XORなどの問題を複雑にするために決定されている理由を見つけるのに苦労しています。残念ながら、IMO単純なコードではなくトリッキーなコード。
_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の呼び出しによってキャストを置き換えました