Ответ 1
Не используйте %
. Это проблема, которая вызывает битмаски:
bool same_parity = (i & 0x1) == (j & 0x1);
Это работает независимо от знака i
, так как результат этого выражения всегда будет 0
или 1
.
У меня есть 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
.
Не используйте %
. Это проблема, которая вызывает битмаски:
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
в противном случае.
Это работает на любой комбинации беззнаковых чисел, 2s-дополнения и знака и величины, но не на редком 1s-дополнении, если ровно один отрицательный.
Добавление двух целых чисел добавляет их четность, поэтому решение просто:
if ( (j + m) % 2 )
Unsigned wraparound не нарушает это свойство, так как оно выполнено по модулю UINT_MAX+1
, которое является четным числом.
Это решение не зависит от каких-либо специфических для реализации деталей, таких как представление отрицательных чисел.
Сноска: я изо всех сил пытаюсь понять, почему многие другие ответы усложняют проблему с помощью бит-сдвигов, бит-дополнений, XOR и т.д. и т.д. К сожалению, IMO иногда прославляется в C или С++ сообщества писать хитрый код вместо простого кода.
При отливке unsigned int
, превышающей INT_MAX
до int
, не гарантируется возврат разумного значения. Результатом является undefined.
Приведение int
к unsigned int
всегда приводит к определенному поведению - для математики mod 2^k
для m k
достаточно большой, чтобы каждый положительный int
был меньше 2^k
.
if((int(j)+m)%2)
должен быть
if((j+unsigned(m))%2)
вместо.
if((j%2)==(unsigned(m)%2))
- самый простой способ увидеть, имеют ли обе одинаковые четности. Переход к unsigned aka mod 2^k
будет сохранять четность, а в unsigned %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
Это можно упростить:
if(!(j%2)!=!(m%2))
if(bool(j%2)!=bool(j%2))
в
if ((abs(m) % 2) != (j % 2))
обязательно включите math.h
#include <math.h>
Абсолютное значение приведет к удалению знакового бита, который является самым левым в памяти.
Преобразование подписанного в unsigned в порядке и определено на C99.
Нашел этот ресурс.
Побитовые операторы также должны работать с компилятором C99, а подписанное с меньшим максимальным значением преобразуется в большее (подписанное без знака).
Абсолютное значение, чтобы игнорировать его подпись или без знака. Затем манипулируйте, чтобы определить, будет ли разделение на два (тестовая четность) вернуть остаток или нет.
Итак, функция, которая сделает что-то вроде этого для любого числа, будет:
#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 будет инициализировано в функции.