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



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

513   18  

18 ответов:

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

Примечание: поскольку мы используем exclusive or, мы хотим, чтобы LHS и RHS были разными, когда знаки одинаковы, таким образом, различная проверка против нуля.

что с

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

?

(a ^ b) >= 0

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

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

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

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

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

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

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

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

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

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

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

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

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

(integer1 * integer2) > 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

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

Я думаю, что это скорее зависит от машины, хотя.

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

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

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

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

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

Comments

    Ничего не найдено.