Какой самый простой способ проверить, имеют ли два целых числа один знак? Есть ли короткий побитовый трюк, чтобы сделать это?Самый простой способ проверить, имеют ли два целых числа один и тот же знак?
ответ
Вот версия, которая работает в C/C++, который не зависит от размеров целочисленных или имеют проблему переполнения (т.е. х * у> = 0 не работает)
bool SameSign(int x, int y)
{
return (x >= 0)^(y < 0);
}
Конечно, вы можете выродок и шаблон:
template <typename valueType>
bool SameSign(typename valueType x, typename valueType y)
{
return (x >= 0)^(y < 0);
}
Примечание: Так как мы используем исключающее или, мы хотим, чтобы LHS и RHS быть разными, когда знаки совпадают, следовательно, различные проверки от нуля.
если (х * у)> 0 ...
предполагая ненулевой и такие.
Только от верхней части моей головы ...
int mask = 1 << 31;
(a & mask)^(b & mask) < 0;
если (а * Ь < 0) знак отличается, другой знак же (или или б равен нулю)
Не работает для перелива – 2009-08-17 00:11:33
Предполагая, что 32 бит Интс:
bool same = ((x^y) >> 31) != 1;
Слегка более лаконична:
bool same = !((x^y) >> 31);
Эти два примера кода должны ВСЕГДА ВСЕГДА ВСЕГДА предшествует код комментарий, пожалуйста (в реальной жизни) – 2008-09-15 21:08:20
О, конечно , В реальной жизни я, вероятно, использовал бы что-то вроде этого = Math.Sign (x) == Math.Sign (y). Я просто даю злые битвидические решения, когда люди просят их. : D – Patrick 2008-09-15 23:00:30
Ум, это недопустимый код ... как вы ожидаете `& >>` работать? – 2017-10-04 01:30:39
Возвращаясь к моим университетским дням, в большинстве представлений машин, это не самый левый бит целого числа a 1, когда число отрицательно, и 0, когда оно положительно?
Я полагаю, что это скорее зависит от машины.
(integer1 * integer2)> 0
Потому что, когда два числа разделяют знак, результат умножения всегда будет положительным.
Вы также можете сделать это> = 0, если вы хотите лечить 0 как один и тот же знак независимо от того, что.
Работает только до тех пор, пока продукт не переполнится. – Frosty 2008-09-18 20:55:09
также, умножение может быть довольно медленным ... – 2009-08-16 18:05:31
Если одно из целых чисел равно 0, то у вас есть проблема. – TatiOverflow 2016-12-10 10:18:51
int same_sign =! ((X >> 31)^(y >> 31));
если (same_sign) ... еще ...
В технической записке, бит-twiddly решения будет гораздо более эффективным, чем умножение, даже на современных архитектурах. Это всего лишь около 3 циклов, которые вы сохраняете, но вы знаете, что они говорят о «копейке» ...
спасенная копейка - корень всего зла, скажем, около 97% времени? – ysth 2009-08-16 18:54:21
(a^b) >= 0
оценит 1, если знак такого же, 0 в противном случае.
Я бы с осторожностью относился к любым побитовым трюкам, чтобы определить знак целых чисел, так как тогда вы должны сделать предположения о том, как эти числа представлены внутри.
Почти 100% времени целые числа будут храниться как two's compliment, но не рекомендуется делать предположения о внутренних компонентах системы, если вы не используете тип данных, который гарантирует определенный формат хранения.
В дополнении 2 вы можете просто проверить последний (самый левый) бит в целых числах, чтобы определить, является ли он отрицательным, поэтому вы можете сравнить только эти два бита. Это означало бы, что 0 будет иметь тот же знак, что и положительное число, но это противоречит знаковой функции, реализованной на большинстве языков.
Лично я просто использовал функцию знака выбранного вами языка. Маловероятно, что будут какие-либо проблемы с производительностью с такими расчетами.
Для любого размера междунар с дополнением до двух арифметика:
#define SIGNBIT (~((unsigned int)-1 >> 1))
if ((x & SIGNBIT) == (y & SIGNBIT))
// signs are the same
предполагая 32 бит
если (((х^у) & 0x80000000) == 0)
... ответ, если (x * y> 0) плохо из-за переполнения
Я не уверен, что считаю «поразрядным» и «самым простым» быть синонимом. Я вижу много ответов, которые предполагают подписанные 32-битные целые числа (хотя это будет быть глупым, чтобы просить без знака); Я не уверен, что они применимы к значениям с плавающей запятой.
Похоже, что «простейшая» проверка заключается в сравнении того, как оба значения сравниваются с 0; это довольно общий, если предположить, что типы можно сравнить:
bool compare(T left, T right)
{
return (left < 0) == (right < 0);
}
Если знаки противоположны, вы становитесь ложными. Если знаки совпадают, вы становитесь правдивыми.
Что случилось с
return ((x<0) == (y<0));
?
Предполагая, что двойки дополняют арифметику (http://en.wikipedia.org/wiki/Two_complement):
inline bool same_sign(int x, int y) {
return (x^y) >= 0;
}
Это может занять всего два инструкции и меньше, чем 1ns на современном процессоре с оптимизацией.
не предполагающие двойки дополнение арифметика:
inline bool same_sign(int x, int y) {
return (x<0) == (y<0);
}
Это может потребоваться один или два дополнительных инструкций и занять немного больше времени.
Использование умножения - плохая идея, поскольку она уязвима для переполнения.
внеофисный версия C:
int sameSign(int a, int b) {
return ~(a^b) & (1<<(sizeof(int)*8-1));
}
C++ шаблон для целочисленных типов:
template <typename T> T sameSign(T a, T b) {
return ~(a^b) & (1<<(sizeof(T)*8-1));
}
Лучший способ использования std::signbit следующим образом:
std::signbit(firstNumber) == std::signbit(secondNumber);
Он также поддерживает другие основные типы (double
, float
, char
и т.д).
работает только для 32-битных целых чисел, которые не предусмотренных в вопросе – 2009-08-17 00:10:26