2013-05-23 3 views
2

Я пытаюсь определить следующее и предыдущее четное число с побитовыми операциями.добавить и удалить последний бит

Так, например, для следующей функции:

x nextEven(x) 
1  2 
2  2 
3  4 
4  4 

и предыдущая:

x previousEven(x) 
1  0 
2  2 
3  2 
4  4 

у меня была идея для nextEven функции что-то вроде: value = ((value+1)>>1)<<1;

И для previousEven функционирует примерно так: value = ((value)>>1)<<1

есть лучший подход ?, без сравнения и просмотра, если значения четные или нечетные.

спасибо.

+2

Лучший подход _is_ сравнение значений, чтобы увидеть, четные или нечетные. Такие хитрости могут показаться умными, но они редко бывают. Сначала оптимизируйте для удобства чтения. Только перейдите к оптимизации производительности, когда вы определили конкретное узкое место. Я гарантирую, что разница между compare/set и multi-bit-ops не стоит по сути незаменимого кода. – paxdiablo

ответ

4

Выполнение сдвига вправо, за которым следует сдвиг влево, чтобы очистить LSB, не очень эффективно.

Я хотел бы использовать что-то вроде:

previous: value &= ~1; 
next: value = (value +1) & ~1; 

~1 может (и обычно будет) быть предварительно вычислены во время компиляции, так что previous будет в конечном итоге, как один побитовое операции на run- время. next, вероятно, закончится двумя операциями (приращение, and), но все равно должно быть довольно быстро.

О том, что вы можете надеяться из-за сдвигов, заключается в том, что компилятор узнает, что вы просто явно LSB, и оптимизируйте его до того, что вы ожидаете от этого.

+0

Я не думаю, что «предыдущий: значение &= ~1;» работает. Если «значение» имеет исходное значение 2, выполнение «previous: value &= ~1;» будет оставаться на 2, а не на желаемое значение 0. Рекомендовать вместо этого «previous: value = (value - 1) & ~1;» – chux

+3

@chux : Согласно таблице в вопросе, для ввода 2, желаемый результат «предыдущего четного» равен 2. –

+0

Я сижу исправлен. – chux

1

Предположим, вы используете unsigned int s, предыдущий даже (соответствующий вашим значениям - мы можем спорить о том, должно ли предыдущее даже из 2 должно быть 0 и т. Д.) - это просто x & ~1u. Дальше даже предыдущий даже из x + 1.

1

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

Самое лучшее, что вы можете сделать, как разработчик, чтобы оптимизировать для удобства чтения первой и только снасти производительности, как только вы определили конкретные узкое место, которое вызывает реальные проблемы.

Лучший код для получения предыдущего четного числа (по вашему определению, где предыдущее четное число 2 в 2) просто писать что-то вроде:

if ((num % 2) == 1) num--; // num++ for next. 

или (чуть более продвинутый):

num -= num % 2;   // += for next. 

и позволяя безумным оптимизаторам составить лучший базовый код.

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

+0

Я согласен с вашей философией разработчика, но вопроситель спросил, как это сделать с побитовыми операциями. Таким образом, бит-решение лучше отвечает на запрос. (Хотя я думаю, что было бы очень сложно создать побитовое решение.) – chux

+0

Мне это сложнее понять, чем код OPs. – harold

+0

@harold, вам будет труднее увидеть, что вычитание одного из нечетного числа дает вам следующее самое низкое четное число? И все же у вас нет проблем со сдвигом-правом/сдвигом-левым? Возможно, вы слишком долго работали на слишком низком уровне :-) – paxdiablo

3

вы могли бы сделать что-то вроде этого

за предыдущие даже

unsigned prevev(unsigned x) 
{ 
    return x-(x%2);//bitwise counterpart x-(x&1); 
} 

для следующего четного

unsigned nxtev(unsigned x) 
{ 
    return (x%2)+x; //bitwise counterpart x+(x&1); 
} 
+0

@downvoter, почему downvote? Atleast оставить комментарий, когда вы downvoting –

0
unsigned int previous(unsigned int x) 
{ 
    return x & 0xfffffffe; 
} 

unsigned int next(unsigned int x) 
{ 
    return previous(x + 2); 
} 
+2

вы считаете, что unsigned int - 32 бита. вместо этого используйте '~ 1' за магическое число, в котором вы будете в безопасности :) –

1

Предыдущая четного:
Для предыдущего четного числа I пр EFER Jerry Coffin «s answer

// Get previous even number 
unsigned prevEven(unsigned no) 
{ 
    return (no & ~1); 
} 

Следующая даже номер:
Я стараюсь использовать только побитовое оператор, но до сих пор я использую один унарный минус - оператор, чтобы получить следующий номер().

// Get next even number 
unsigned nextEven(unsigned no) 
{ 
    return (no & 1) ? (-(~no)) : no ; 
} 

Рабочая Метода nextEven():

  • Если номер не даже возвращает тот же номер,
    , если нет даже это LSB является 0 иначе 1
    Получить LSB числа = >number & 1
  • Если число нечетное, возвращайте число + 1,
    Добавить 1 в цифру =>-(~number)
Смежные вопросы