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

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

<p>вот версия, которая работает на c/c++, которая не зависит от целочисленных размеров или имеет проблему переполнения (то есть x * y> = 0 не работает)</p><pre><code>bool samesign(int x, int y) { return (x >= 0) ^ (y < 0); } </code></pre><p>конечно, вы можете получить и шаблон:</p><pre><code>template <typename valuetype> bool samesign(typename valuetype x, typename valuetype y) { return (x >= 0) ^ (y < 0); } </code></pre><p>примечание. так как мы используем исключительные или, мы хотим, чтобы lhs и rhs были разными, когда знаки одинаковы, таким образом, различная проверка на ноль.</p>

<p>что случилось с</p><pre><code>return ((x<0) == (y<0)); </code></pre><p>?</p>

<pre><code>(a ^ b) >= 0 </code></pre><p>будет иметь значение 1, если знак совпадает, 0 в противном случае.</p>

<p>я бы с осторожностью относился к любым побитовым трюкам для определения знака целых чисел, так как тогда вы должны делать предположения о том, как эти числа представляются внутри.</p><p>почти 100% времени целые числа будут храниться как <a href="http://en.wikipedia.org/wiki/twos\_compliment">комплимент двоих</a> , но не рекомендуется делать предположения о внутренностях системы, если вы не используете тип данных, который гарантирует определенный формат хранения.</p><p>в дополнение к двум вы можете просто проверить последний (самый левый) бит в целом числе, чтобы определить, является ли он отрицательным, так что вы можете сравнить только эти два бита. это будет означать, что знак 0 будет иметь тот же знак, что и положительное число, что противоречит функции знака, реализованной в большинстве языков.</p><p>лично я бы просто использовал функцию знака на выбранном вами языке. маловероятно, что при таком расчете возникнут какие-либо проблемы с производительностью.</p>

<p>предполагая 32-битные целые:</p><pre><code>bool same = ((x ^ y) >> 31) != 1; </code></pre><p>чуть более кратко:</p><pre><code>bool same = !((x ^ y) >> 31); </code></pre>

<p>я не совсем уверен, что считаю "битовый трюк" и "самый простой" синонимами. я вижу много ответов, в которых предполагается, что 32-разрядные целые числа со знаком (хотя это <em> было бы </em> глупо запрашивать без знака); я не уверен, что они применимы к значениям с плавающей точкой.</p><p>кажется, что самой простой проверкой было бы сравнить оба значения с 0; это довольно обобщенно, если предположить, что типы можно сравнивать:</p><pre><code>bool compare(t left, t right) { return (left < 0) == (right < 0); } </code></pre><p>если знаки противоположны, вы получаете ложь. если знаки совпадают, вы получите правду.</p>

<p>(integer1 * integer2)> 0</p><p>потому что, когда два целых числа разделяют знак, результат умножения всегда будет положительным.</p><p>вы также можете сделать это> = 0, если вы хотите рассматривать 0 как один и тот же знак, несмотря ни на что.</p>

<p>предполагая, что двойки дополняют арифметику ( <a href="http://en.wikipedia.org/wiki/two\_complement">http://en.wikipedia.org/wiki/two\_complement</a> ):</p><pre><code>inline bool same\_sign(int x, int y) { return (x^y) >= 0; } </code></pre><p>это может занять всего две инструкции и менее 1 нс на современном процессоре с оптимизацией.</p><p>не предполагая, что двойки дополняют арифметику:</p><pre><code>inline bool same\_sign(int x, int y) { return (x<0) == (y<0); } </code></pre><p>это может потребовать одну или две дополнительные инструкции и занять немного больше времени.</p><p>использование умножения - плохая идея, потому что оно уязвимо для переполнения.</p>

<p>если (х * у)> 0 ...</p><p>при условии ненулевой и тому подобное.</p>

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

<p>версия c без ответвлений:</p><pre><code>int samesign(int a, int b) { return ~(a^b) & (1<<(sizeof(int)*8-1)); } </code></pre><p>шаблон c++ для целочисленных типов:</p><pre><code>template <typename t> t samesign(t a, t b) { return ~(a^b) & (1<<(sizeof(t)*8-1)); } </code></pre>

<p>просто с моей головы ...</p><pre><code>int mask = 1 << 31; (a & mask) ^ (b & mask) < 0; </code></pre>

<p>для любого размера int с арифметикой с двумя дополнениями:</p><pre><code>#define signbit (~((unsigned int)-1 >> 1)) if ((x & signbit) == (y & signbit)) // signs are the same </code></pre>

<p>при условии 32 бит</p><p><code>if(((x^y) & 0x80000000) == 0)</code></p><p>... ответ <code>if(x*y>0)</code> плохой из-за переполнения</p>

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

<p>вспоминая мои университетские дни, в большинстве представлений о машинах не является ли левый бит целого числа 1, когда число отрицательное, и 0, когда оно положительное?</p><p>я полагаю, что это скорее зависит от машины.</p>

<p>int same\_sign =! ((x >> 31) ^ (y >> 31));</p><p>if (same\_sign) ... еще ...</p>

<p>лучше использовать <a href="http://en.cppreference.com/w/cpp/numeric/math/signbit">std :: signbit</a> следующим образом:</p><pre><code>std::signbit(firstnumber) == std::signbit(secondnumber); </code></pre><p>он также поддерживает другие основные типы (<code>double</code>, <code>float</code>, <code>char</code> и т.д.).</p>