Подтвердить что ты не робот

Проверьте, не является ли число с нулевым значением с помощью побитовых операторов в C

Проверьте, является ли число x ненулевым, используя законные операторы, кроме !.

Примеры: isNonZero(3) = 1, isNonZero(0) = 0

Правовые операции: ~ & ^ | + << >>

  • Примечание. Следует использовать только побитовые операторы. if, else, for и т.д. не могут быть использованы.
  • Edit1: количество операторов не должно превышать 10.
  • Edit2: размер int должен быть 4 байта.

int isNonZero(int x) {
return ???;
}

Используя !, это было бы тривиально, но как мы это сделаем, не используя !?

4b9b3361

Ответ 1

Логарифмическая версия функции adamk:

int isNotZero(unsigned int n){
  n |= n >> 16;
  n |= n >> 8;
  n |= n >> 4;
  n |= n >> 2;
  n |= n >> 1;
  return n & 1;
};

И самый быстрый, но в сборке:

xor eax, eax
sub eax, n  // carry would be set if the number was not 0
xor eax, eax
adc eax, 0  // eax was 0, and if we had carry, it will became 1

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

EDIT: вот самая быстрая версия, о которой я могу думать в C:

1) для отрицательных чисел: если бит знака установлен, число не равно 0.

2) для положительного: 0 - n будет отрицательным и может быть проверен как в случае 1. Я не вижу - в списке юридических операций, поэтому мы будем использовать ~n + 1 вместо,

Что мы получаем:

int isNotZero(unsigned int n){ // unsigned is safer for bit operations
   return ((n | (~n + 1)) >> 31) & 1;
}

Ответ 2

int isNonZero(unsigned x) {
    return ~( ~x & ( x + ~0 ) ) >> 31;
}

Предполагая, что int - 32 бита (/* EDIT: эта часть больше не применяется, когда я изменил тип параметра на unsigned */, и что подписанные смены ведут себя точно так же, как беззнаковые).

Ответ 3

Почему сложнее?

int isNonZero(int x) {
    return x;
}

Это работает, потому что соглашение C состоит в том, что каждое ненулевое значение означает true, а isNonZero возвращает int, что является законным.

Некоторые люди утверждали, что функция isNonZero() должна возвращать 1 для ввода 3, как показано в примере.

Если вы используете С++, это все равно так же просто:

int isNonZero(int x) {
    return (bool)x;
}

Теперь функция возвращает 1, если вы предоставляете 3.

ОК, он не работает с C, который пропускает правильный логический тип.

Теперь, если вы предположили, что ints 32 бита и + разрешено:

int isNonZero(int x) {
    return ((x|(x+0x7FFFFFFF))>>31)&1;
}

На некоторых архитектурах вы можете даже избежать окончательного &1, просто переведя x в unsigned (который имеет нулевую стоимость исполнения), но это Undefined Behavior, поэтому зависит от реализации (зависит от того, использует ли целевая архитектура подписанную или логический сдвиг вправо).

int isNonZero(int x) {
    return ((unsigned)(x|(x+0x7FFFFFFF)))>>31;
}

Ответ 4

Побитовое ИЛИ все биты в числе:

int isByteNonZero(int x) {
    return ((x >> 7) & 1) |
           ((x >> 6) & 1) |
           ((x >> 5) & 1) |
           ((x >> 4) & 1) |
           ((x >> 3) & 1) |
           ((x >> 2) & 1) |
           ((x >> 1) & 1) |
           ((x >> 0) & 1);
}

int isNonZero(int x) {
  return isByteNonZero( x >> 24 & 0xff ) |
         isByteNonZero( x >> 16 & 0xff ) |
         isByteNonZero( x >> 8  & 0xff ) |
         isByteNonZero( x       & 0xff );
}

Ответ 5

int is_32bit_zero( int x ) {
    return 1 ^ (unsigned) ( x + ~0 & ~x ) >> 31;
}
  • Вычитание 1. (~0 генерирует минус один на машине с двумя дополнениями. Это предположение.)
  • Выберите только перевернутый бит, который перевернулся на один.
  • Самый значительный бит только переворачивается в результате вычитания, если x равен нулю.
  • Переместить самый старший бит в младший бит.

Я считаю шесть операторов. Я мог бы использовать 0xFFFFFFFF для пяти. Приведение к unsigned не относится к машине с двумя дополнениями, v).

http://ideone.com/Omobw

Ответ 6

в основном вам нужно или бит. Например, если вы знаете, что ваш номер имеет ширину 8 бит:

int isNonZero(uint8_t x)
{
    int res = 0;
    res |= (x >> 0) & 1;
    res |= (x >> 1) & 1;
    res |= (x >> 2) & 1;
    res |= (x >> 3) & 1;
    res |= (x >> 4) & 1;
    res |= (x >> 5) & 1;
    res |= (x >> 6) & 1;
    res |= (x >> 7) & 1;

    return res;
}

Ответ 7

Мое решение следующее:

int isNonZero(int n)
{
    return ~(n == 0) + 2;
}

Ответ 8

Мое решение в C. Нет оператора сравнения. Не работает с 0x80000000.

#include <stdio.h>

int is_non_zero(int n) {
    n &= 0x7FFFFFFF;
    n *= 1;
    return n;
}

int main(void) {
    printf("%d\n", is_non_zero(0));
    printf("%d\n", is_non_zero(1));
    printf("%d\n", is_non_zero(-1));
    return 0;
}

Ответ 9

Мое решение, хотя и не совсем связанное с вашим вопросом

int isSign (int x)

{
//return 1 if positive,0 if zero,-1 if negative
return (x > 0) - ((x & 0x80000000)==0x80000000)
}

Ответ 10

Эта функция вернет x, если она отлична от нуля, иначе она вернет 0.

int isNonZero(int x)
{
    return (x);
}

Ответ 11

Следующий пример функции должен работать для вас.

bool isNonZero(int x)
{
    return (x | 0);
}

Ответ 12

if(x)
     printf("non zero")
else
     printf("zero")

Ответ 13

int isNonZero (int x)

{

if (  x & 0xffffffff)
    return 1;
else
    return 0;

}

Предположим, что Int - это 4 байта.

Он вернет 1, если значение равно нулю

если значение равно нулю, оно вернет 0.

Ответ 14

return ((val и 0xFFFFFFFF) == 0? 0: 1);