LINUX.ORG.RU

Битовые операции: обнулить младшие биты числа


0

2

Разминка для МОЗГа.

Как с помощью битовых операций | & ~ и скобок обнулить все младшие биты числа. Т.е., например, в результате данного преобразования, число 0b10101111 должно превратиться в 0b10000000. Число от 0 до 2^64-1.

Если такое вообще реально. Условные операторы использовать нельзя.

Upd.:Сдвиги использовать можно. Забыл сказать

★★★★★

Последнее исправление: ttnl (всего исправлений: 1)

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

unC0Rr ★★★★★
()
#include <stdio.h>

int
main()
{
        int     a = 0b10101111;
        int     b = 0b10000000;

        a &= ~(a & ~(1 << 7));

        printf("%d %d\n", a, b);
}
beastie ★★★★★
()
Ответ на: комментарий от yoghurt

> вообще тупо long long a = 0x8000000000000000

именно тупо, нужно использовать uint64_t, или __int64 для Wыn32

anonymous
()
Ответ на: комментарий от yoghurt

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

yoghurt ★★★★★
()
Ответ на: комментарий от madcore

>Если я правильно понял ТС, то ему нужно обнулить младшие 8 бит?

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

Иначе бы и вопроса не возникло :)

Я изящного решения в рамках описанной задачи не вижу.

Хотя условия озвучены недостаточно строго, так что может я и ошибаюсь :)

Например, в каком виде подаётся разрядность?

KRoN73 ★★★★★
()
Ответ на: комментарий от yoghurt

>Сдвиги использовать можно?

Можно, забыл сказать

ttnl ★★★★★
() автор топика
Ответ на: комментарий от Eddy_Em

>Почитать K&R. Задание для лабораторки наверняка по ней составляли :)

Я уж давно не студент :)

ttnl ★★★★★
() автор топика
Ответ на: комментарий от anon_666

>Те «старший» бит на произвольной позиции, или нет?

На произвольной

ttnl ★★★★★
() автор топика
Ответ на: комментарий от note173

>0b10101111 & 0b10000000 разве не подходит?

Нет, потому что

Число от 0 до 2^64-1

ttnl ★★★★★
() автор топика

(из работающего кода) fw - требуемое число

                int pow2 = 0;
                while(fw != 1){
                        fw >>= 1;
                        pow2++;
                }
                fw = (1 << pow2);
Если не использовать условные операторы - придется возиться с булевой логикой.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от madcore

>Если я правильно понял ТС, то ему нужно обнулить младшие 8 бит?

Ты неправильно понял. Там же написано, что число максимально 2^64-1. Нужно обнулить все младшие биты

ttnl ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

Да Вы правильно поняли.

Например, в каком виде подаётся разрядность?

Число произвольное u64. Сдвиги использовать можно

ttnl ★★★★★
() автор топика
Ответ на: комментарий от Eddy_Em

while — условный оператор.

ttnl ★★★★★
() автор топика
Ответ на: комментарий от Eddy_Em

>Без условного оператора от сдвигов толку 0.

Как это? Зачем условный оператор при наличии сдвигов?

KRoN73 ★★★★★
()
#include <stdio.h>

#define doit(x) (x) & (1 << (8 * sizeof (x) - 1))

int main (int argc, char *argv) {
    char  a = 0x12;
    short b = 0x3456;
    int   c = 0xDEADBEEF;

    printf ("%x, %x, %x\n", doit (a), doit (b), doit (c));
    return 0;
}
yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

а, млеат, я тут просто первые биты показываю

yoghurt ★★★★★
()
Ответ на: комментарий от KRoN73

Зачем условный оператор при наличии сдвигов?

А как вы проверите, что достигнут предел? (см. мой пример)

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от KRoN73

>Тю. Тогда задача не интересна :)

И какое решение? ;)

ttnl ★★★★★
() автор топика
Ответ на: комментарий от yoghurt

>И что, для 64битного числа проканает?)

Если написать return a & (~0xffULL), то должно проканать.

prischeyadro ★★★☆☆
()
Ответ на: комментарий от KRoN73

Тю. Тогда задача не интересна :)

А как? Мне пока ничего в голову не приходит, кроме разворота в одно выражение подобного говноцикла:

u64 oldbit=0;
for (i=63;i>=0;i--){
    a&=~oldbit;
    oldbit|=a&((1<<i));
    oldbit>>=1;
}    
madcore ★★★★★
()
Ответ на: комментарий от madcore

Циклы использовать нельзя ;)

У меня пока есть такое решение:


(...((x & (~(x >> 1))) & (~(x >> 2))...&(~(x>>63))

ttnl ★★★★★
() автор топика
Ответ на: комментарий от ttnl

Но оно наверняка неоптимальное

ttnl ★★★★★
() автор топика
Ответ на: комментарий от ttnl

>Циклы использовать нельзя ;)

Так я и написал про разворот того цикла. В итоге это и получится:

(...((x & (~(x >> 1))) & (~(x >> 2))...&(~(x>>63))

madcore ★★★★★
()
Ответ на: комментарий от madcore

>А как? Мне пока ничего в голову не приходит, кроме разворота в одно выражение подобного говноцикла

Его и имел в виду. Некрасиво, но условия выполняет :)

KRoN73 ★★★★★
()
Ответ на: комментарий от madcore

Да, правильно. Я сразу не въехал

ttnl ★★★★★
() автор топика
Ответ на: комментарий от twosev

>Но в условии не было минуса.

Минус эмулируется через базовую логику. Но будет ещё сложнее, чем в варианте с раскрученным циклом :)

KRoN73 ★★★★★
()
Ответ на: комментарий от madcore

В общем случае заменять операции таким образом нельзя. Но в данном примере к последней строке x имеет значение ob1111...1, то есть сумма соответствующих степеней двоек. Поэтому использование вычитания из этой суммы всех степеней двоек кроме наибольшей вполне корректно.

twosev ★★
()

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

А если мы пишем железо, то число можно представить в виде битового массива, завести 63 каскадных or и поandить... Ну, или, если по скорости оптимизировать, то сделать побольше оров потолще и параллельно их...

Yareg ★★★
()
Ответ на: комментарий от madcore

В данном случае число x имеет вид 0b111...111. Пусть в нем n единиц. Тогда вычитается из него число, состоящее из (n-1) единиц. То есть 0b1111 - 0b0111 == 0b1000.

twosev ★★
()
Ответ на: а вообще от madcore

А вообще :)

#include <stdint.h>
#include <stdio.h>

unsigned uint64_highest_bit_pos(uint64_t vect)
{
#if (defined (__x86_64__) || defined (__x86_64) || defined (__amd64))
  uint64_t pos = 0;
  asm volatile ( "bsrq %0, %0;"
                    : "=r" (pos)
                    :  "0" (vect) );
  return (unsigned)pos;
#else
  unsigned shift = 32;
  unsigned pos, v32 = (vect >> 32) & 0xffffffff;
  if (!v32) {
    v32   = vect                   & 0xffffffff;
    shift = 0;
  }
  asm volatile ( "bsrl %0, %0;"
                    : "=r" (pos)
                    :  "0" (v32) );
  pos += shift;
  return pos;
#endif
}

int main(int argc, char *argv[])
{
    uint64_t x = atoll(argv[1]);
    if (x) x = 1 << uint64_highest_bit_pos(x);
    printf("%lu\n", x);
}
twosev ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.