Проверка, является ли число положительным или отрицательным, используя побитовые операторы - PullRequest
30 голосов
/ 23 сентября 2010

Я могу проверить, является ли число нечетным / четным, используя побитовые операторы.Могу ли я проверить, является ли число положительным / нулевым / отрицательным без использования каких-либо условных операторов / операторов, таких как if / ternary и т. Д.

Можно ли сделать то же самое с помощью побитовых операторов и некоторого трюка в C или в C ++?

Ответы [ 15 ]

27 голосов
/ 23 сентября 2010

Могу ли я проверить, является ли число положительным / нулевым / отрицательным, без использования каких-либо условных операторов / операторов, таких как if / ternary и т. Д.

Конечно:

bool is_positive = number > 0;
bool is_negative = number < 0;
bool is_zero = number == 0;
16 голосов
/ 23 сентября 2010

Если старший бит установлен для целого числа со знаком (байта, длинной и т. Д., Но не числа с плавающей запятой), это число является отрицательным.

int x = -2300;  // assuming a 32-bit int

if ((x & 0x80000000) != 0)
{
    // number is negative
}

ДОБАВЛЕНО:

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

int isNegative = (x & 0x80000000);

И через некоторое время вы можете проверить это с помощью if (isNegative).

11 голосов
/ 09 октября 2013

Или, вы можете использовать signbit(), и работа сделана для вас.

Я предполагаю, что реализация под капотом math.h - эффективная побитовая проверкавозможно решение вашей первоначальной цели).

Ссылка: http://en.cppreference.com/w/cpp/numeric/math/signbit

11 голосов
/ 23 сентября 2010

Подробное обсуждение на странице Bit Twiddling Hacks .

int v;      // we want to find the sign of v
int sign;   // the result goes here 

// CHAR_BIT is the number of bits per byte (normally 8).
sign = -(v < 0);  // if v < 0 then -1, else 0. 
// or, to avoid branching on CPUs with flag registers (IA32):
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// or, for one less instruction (but not portable):
sign = v >> (sizeof(int) * CHAR_BIT - 1); 

// The last expression above evaluates to sign = v >> 31 for 32-bit integers.
// This is one operation faster than the obvious way, sign = -(v < 0). This
// trick works because when signed integers are shifted right, the value of the
// far left bit is copied to the other bits. The far left bit is 1 when the value
// is negative and 0 otherwise; all 1 bits gives -1. Unfortunately, this behavior
// is architecture-specific.

// Alternatively, if you prefer the result be either -1 or +1, then use:

sign = +1 | (v >> (sizeof(int) * CHAR_BIT - 1));  // if v < 0 then -1, else +1

// On the other hand, if you prefer the result be either -1, 0, or +1, then use:

sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// Or, for more speed but less portability:
sign = (v != 0) | (v >> (sizeof(int) * CHAR_BIT - 1));  // -1, 0, or +1
// Or, for portability, brevity, and (perhaps) speed:
sign = (v > 0) - (v < 0); // -1, 0, or +1

// If instead you want to know if something is non-negative, resulting in +1
// or else 0, then use:

sign = 1 ^ ((unsigned int)v >> (sizeof(int) * CHAR_BIT - 1)); // if v < 0 then 0, else 1

// Caveat: On March 7, 2003, Angus Duggan pointed out that the 1989 ANSI C
// specification leaves the result of signed right-shift implementation-defined,
// so on some systems this hack might not work. For greater portability, Toby
// Speight suggested on September 28, 2005 that CHAR_BIT be used here and
// throughout rather than assuming bytes were 8 bits long. Angus recommended
// the more portable versions above, involving casting on March 4, 2006.
// Rohit Garg suggested the version for non-negative integers on September 12, 2009. 
.
4 голосов
/ 30 сентября 2011
#include<stdio.h>

void main()
{
    int n;  // assuming int to be 32 bit long

    //shift it right 31 times so that MSB comes to LSB's position
    //and then and it with 0x1
    if ((n>>31) & 0x1 == 1) {
        printf("negative number\n");
    } else {
        printf("positive number\n");
    }

    getch();
}
3 голосов
/ 25 мая 2013

Это довольно просто

Это может быть легко сделано

return ((!!x) | (x >> 31));

возвращает

  • 1 для положительного числа,
  • -1 для негатива и
  • 0 для нуля
3 голосов
/ 23 сентября 2010

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

Как правило, это мало что дает, поскольку для использования этой информации необходимо провести какое-то сравнение, и процессору так же легко проверить, является ли что-то отрицательным, как проверить,это не ноль.Если речь идет о процессорах ARM, проверка старшего значащего бита будет обычно БОЛЬШЕ дороже, чем проверка, является ли он отрицательным сразу.

2 голосов
/ 08 марта 2018

Вот обновление, связанное с C ++ 11 для этого старого вопроса.Также стоит учитывать std :: signbit .

В обозревателе компилятора, использующем gcc 7.3 64bit с оптимизацией -O3, этот код

bool s1(double d)
{
    return d < 0.0;
}

генерирует

s1(double):
  pxor xmm1, xmm1
  ucomisd xmm1, xmm0
  seta al
  ret

И этот код

bool s2(double d)
{
    return std::signbit(d);
}

генерирует

s2(double):
  movmskpd eax, xmm0
  and eax, 1
  ret

Вам необходимо выполнить профилирование, чтобы убедиться, что есть какая-либо разница в скорости, но версия signbit действительно использует на 1 код операции меньше.

2 голосов
/ 23 апреля 2013
// if (x < 0) return -1
// else if (x == 0) return 0
// else return 1
int sign(int x) {
  // x_is_not_zero = 0 if x is 0 else x_is_not_zero = 1
  int x_is_not_zero = (( x | (~x + 1)) >> 31) & 0x1;
  return (x & 0x01 << 31) >> 31 | x_is_not_zero; // for minux x, don't care the last operand 
}

Вот именно то, что вы хотите!

1 голос
/ 08 ноября 2015

Более простой способ выяснить, является ли число положительным или отрицательным: пусть число будет х, проверьте, если [x * (-1)]> х.если истина х отрицательна, иначе положительна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...