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

StackOverflow https://stackoverflow.com/questions/66882

  •  09-06-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

Вот версия, работающая на 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);
}

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

Другие советы

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

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

?

(a ^ b) >= 0

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

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

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

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

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

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

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

Чуть более лаконично:

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

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

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

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

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

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

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

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

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

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

Использование умножения — плохая идея, поскольку оно уязвимо к переполнению.

если (x * y) > 0...

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

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

Просто из головы...

int mask = 1 << 31;
(a & mask) ^ (b & mask) < 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));
}

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

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

предполагая 32 бит

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

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

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

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

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

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

если (тот же_знак) ...еще ...

Лучший способ использовать станд::сигбит следующее:

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top