Определение того, являются ли целое со знаком и без знака четным или нечетным
У меня есть int m
и unsigned int j
и хотите определить, являются ли они оба четными или оба нечетными.
В прошлом я использовал
if((int(j)+m)%2)
чтобы поймать случай, что только один нечетен. Но я обеспокоен кастингом на int
неправильно изменяя нечетность-четность j
,
Есть ли у кого-нибудь из них проблемы?
if(!(j%2)!=!(m%2))
if(bool(j%2)!=bool(j%2))
я знаю это
if(j%2!=m%2)
не работает, потому что "m%2" будет производить -1
когда m
отрицательный, который всегда будет оценивать true
независимо от того, что значение j%2
является.
7 ответов
Не использовать %
, Это проблема, которая требует битовых масок:
bool same_parity = (i & 0x1) == (j & 0x1);
Это работает независимо от знака i
, поскольку результат этого выражения всегда будет 0
или же 1
,
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
не имеет значения, мы все равно не смотрим на них). поскольку 1
на самом деле ...0001
, 1 & (i ^ j)
оценивает 0
если i
а также j
оба четные или нечетные, и 1
иначе.
Это работает с любой комбинацией чисел без знака, дополнения 2 с и знака и величины, но не с редким дополнением 1 с, если ровно одно отрицательное.
Добавление двух целых чисел добавляет их четность, поэтому решение просто:
if ( (j + m) % 2 )
Неподписанный перенос не нарушает это свойство, так как выполняется по модулю UINT_MAX+1
который является четным числом.
Это решение не зависит от каких-либо специфических для реализации деталей, таких как представление отрицательных чисел.
Сноска. Я изо всех сил пытаюсь понять, почему так много других ответов решают усложнить проблему сдвигами битов, дополнениями битов, XOR и т. Д. И т. Д. К сожалению, IMO иногда прославляется в сообществах C или C++ для написания хитрый код вместо простого кода.
Кастинг unsigned int
это больше чем INT_MAX
в int
не гарантируется возвращение разумного значения. Результат не определен.
Кастинг int
для unsigned int
всегда приводит к определенному поведению - это делает математику mod 2^k
для некоторых k
достаточно большой, чтобы каждый положительный int
меньше чем 2^k
,
if((int(j)+m)%2)
должно быть
if((j+unsigned(m))%2)
вместо.
if((j%2)==(unsigned(m)%2))
это самый простой способ узнать, имеют ли оба одинаковый паритет. Переезд в неподписанный ака mod 2^k
собирается сохранить паритет и в неподписанном %2
возвращает четность правильно (а не отрицательную четность).
Не будь слишком умным
Есть ли у кого-нибудь из них проблемы?
if(!(j%2)!=!(m%2))
if(bool(j%2)!=bool(j%2))
Одна проблема, которую я вижу, это читабельность. Для кого-то (или вашего будущего я) может быть не очевидно, что он должен делать или что он на самом деле делает.
Вы могли бы быть более выразительными, потратив несколько дополнительных строк:
#include <cmath>
const bool fooIsEven = foo % 2 == 0;
const bool barIsEven = std::abs(bar) % 2 == 0;
if (fooIsEven == barIsEven)
{
// ...
}
Также рассмотрите реализацию правильно названной функции, которая обеспечивает сравнение четности двух данных целочисленных типов. Это не только очищает ваш код, но и предотвращает повторение.
Изменить: Заменить приведение при вызове std::abs
Абсолютное значение, чтобы не учитывать, подписано оно или нет. Затем манипулируйте, чтобы определить, вернет ли деление на два (проверка четности) остаток или нет.
Итак, функция, которая будет делать что-то подобное для любого числа, будет:
#include <stdlib.h>
int x = -4;
unsigned int = 5;
bool isEven(int number){
bool result = false;
int temp = abs(number);
if (temp % 2 != 1){
result = true; }
else {
result = false; }
return result;
}
Обратите внимание, что функция возвращает логическое значение - true, если число четное, и false, если значение нечетное.
Конечно, возвращаемое по умолчанию значение будет false, как инициализировано в функции.
Это может быть упрощено:
if(!(j%2)!=!(m%2))
if(bool(j%2)!=bool(j%2))
чтобы:
if ((abs(m) % 2) != (j % 2))
обязательно включите math.h
#include <math.h>
Абсолютное значение уберет знаковый бит, который является самым левым битом в памяти.
Преобразование подписанного в неподписанное в порядке и определено в C99.
Нашел этот ресурс.
Битовые операторы также должны работать с компилятором C99, и подпись, имеющая меньшее максимальное значение, преобразуется в большее (подписывается в беззнаковое).