it-swarm-ru.tech

Самый простой способ проверить, имеют ли два целых числа один и тот же знак?

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

60
Gerber

Вот версия, которая работает на 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 были разными, когда знаки одинаковы, таким образом, различная проверка на ноль.

47
Torlack

Что случилось с

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

?

202
Rik
(a ^ b) >= 0

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

23
Chris Jobson

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

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

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

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

12
SpoonMeiser

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

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

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

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

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

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

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

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

5
OwenP

(integer1 * integer2)> 0

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

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

4
Benjamin Autin

Предполагая, что двойки дополняют арифметику ( 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);
}

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

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

4
user10315

если (х * у)> 0 ...

при условии ненулевой и тому подобное.

3
Yes - that Jake.

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

2
Daniel Spiewak

версия 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));
}
1
CAFxX

Просто с моей головы ...

int mask = 1 << 31;
(a & mask) ^ (b & mask) < 0;
1
Daniel Spiewak

Для любого размера int с арифметикой с двумя дополнениями:

#define SIGNBIT (~((unsigned int)-1 >> 1))
if ((x & SIGNBIT) == (y & SIGNBIT))
    // signs are the same
1
Mark Ransom

при условии 32 бит

if(((x^y) & 0x80000000) == 0)

... ответ if(x*y>0) плохой из-за переполнения

1
ugasoft

если (a * b <0) знак другой, иначе знак тот же (или a или b равно нулю)

0
dogfish

Вспоминая мои университетские дни, в большинстве представлений о машинах не является ли левый бит целого числа 1, когда число отрицательное, и 0, когда оно положительное?

Я полагаю, что это скорее зависит от машины.

0
Dana

int same_sign =! ((x >> 31) ^ (y >> 31));

if (same_sign) ... еще ...

0
andrew

Лучше использовать std :: signbit следующим образом:

std::signbit(firstNumber) == std::signbit(secondNumber);

Он также поддерживает другие основные типы (double, float, char и т.д.).

0
ashiquzzaman33