Самый простой способ проверить, имеют ли два целых числа один и тот же знак? - PullRequest
60 голосов
/ 16 сентября 2008

Какой самый простой способ проверить, имеют ли два целых числа один и тот же знак? Есть ли какой-нибудь короткий побитовый трюк для этого?

Ответы [ 18 ]

202 голосов
/ 16 сентября 2008

Что не так с

return ((x<0) == (y<0));  

47 голосов
/ 16 сентября 2008

Вот версия, которая работает на C / C ++, которая не основывается на целочисленных размерах или имеет проблему переполнения (то есть x * y> = 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 были разными, когда знаки одинаковы, и, таким образом, различается проверка на ноль.

23 голосов
/ 16 сентября 2008
(a ^ b) >= 0

будет иметь значение 1, если знак совпадает, в противном случае - 0.

12 голосов
/ 16 сентября 2008

Я бы с осторожностью относился к любым побитовым трюкам для определения знака целых чисел, так как тогда вам придется делать предположения о том, как эти числа представляются внутри.

Почти 100% времени целые числа будут храниться как комплимент для двоих , но не стоит делать предположения о внутренностях системы, если вы не используете тип данных, который гарантирует определенный формат хранения .

В дополнении к двум вы можете просто проверить последний (самый левый) бит в целом числе, чтобы определить, является ли он отрицательным, так что вы можете сравнить только эти два бита. Это будет означать, что знак 0 будет иметь тот же знак, что и положительное число, что противоречит функции знака, реализованной в большинстве языков.

Лично я бы просто использовал функцию знака на выбранном вами языке. Маловероятно, что при таком расчете возникнут какие-либо проблемы с производительностью.

6 голосов
/ 16 сентября 2008

Предполагая 32-битные целые:

bool same = ((x ^ y) >> 31) != 1;

Чуть более кратко:

bool same = !((x ^ y) >> 31);
5 голосов
/ 16 сентября 2008

Я не совсем уверен, что считаю "битовый трюк" и "самый простой" синонимами. Я вижу много ответов, которые предполагают 32-разрядные целые числа со знаком (хотя было бы глупо запрашивать без знака); Я не уверен, что они применимы к значениям с плавающей точкой.

Кажется, что самой простой проверкой было бы сравнить оба значения с 0; это довольно обобщенно, если предположить, что типы можно сравнивать:

bool compare(T left, T right)
{
    return (left < 0) == (right < 0);
}

Если знаки противоположны, вы ошибаетесь. Если знаки совпадают, вы получите правду.

4 голосов
/ 16 сентября 2008

(целое число 1 * целое число 2)> 0

Потому что, когда два целых числа разделяют знак, результат умножения всегда будет положительным.

Вы также можете сделать это> = 0, если хотите трактовать 0 как один и тот же знак, несмотря ни на что.

4 голосов
/ 16 сентября 2008

Предполагая, что арифметика дополняется двумя (http://en.wikipedia.org/wiki/Two_complement):

inline bool same_sign(int x, int y) {
    return (x^y) >= 0;
}

Это может занять всего две инструкции и менее 1 нс на современном процессоре с оптимизацией.

Не предполагая, что арифметика дополняется двумя:

inline bool same_sign(int x, int y) {
    return (x<0) == (y<0);
}

Для этого может потребоваться одна или две дополнительные инструкции и немного больше времени.

Использование умножения - плохая идея, потому что оно уязвимо для переполнения.

3 голосов
/ 16 сентября 2008

if (x * y)> 0 ...

при условии ненулевого значения и т.п.

2 голосов
/ 16 сентября 2008

В качестве технического примечания, побитовые решения будут намного более эффективными, чем умножение, даже на современных архитектурах. Это всего лишь около 3 циклов, которые вы экономите, но вы знаете, что они говорят о «сохраненной копейке» ...

...