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 были разными, когда знаки одинаковы, таким образом, различная проверка против нуля.
Я бы опасался любых побитовых трюков для определения знака целых чисел, так как тогда вам нужно сделать предположения о том, как эти числа представлены внутри.
почти 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); }
Это может потребовать одной или двух дополнительных инструкций и занять немного больше времени.
использование умножения-плохая идея, потому что она уязвима для переполнения.
как техническое замечание, бит-твид-решения будут гораздо более эффективными, чем умножение, даже на современных архитектурах. Это всего лишь около 3 циклов, которые вы сохраняете, но вы знаете, что они говорят о "копейке"...
версия 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
вспоминая мои университетские дни, в большинстве машинных представлений, не является ли самый левый бит целого числа 1, когда число отрицательно, и 0, когда оно положительное?
Я думаю, что это скорее зависит от машины, хотя.
лучше использовать std:: signbit следующим образом:
std::signbit(firstNumber) == std::signbit(secondNumber);
Он также поддерживает другие базовые типы (
double
,float
,char
etc).
Comments