Определение того, являются ли целое со знаком и без знака четным или нечетным

У меня есть 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, и подпись, имеющая меньшее максимальное значение, преобразуется в большее (подписывается в беззнаковое).

Другие вопросы по тегам