возвращает x с n битами, которые начинаются с позиции p, установленной на самые правые n битов y, оставляя другие биты без изменений - PullRequest
2 голосов
/ 18 июля 2011

мое решение

get the rightmost n bits of y
a = ~(~0 << n) & y

clean the n bits of x beginning from p
c = ( ~0 << p | ~(~0 << (p-n+1))) & x

set the cleaned n bits to the n rightmost bits of y
c | (a << (p-n+1))

это довольно длинные высказывания. у нас есть лучший?

 i.e
x = 0 1 1 1 0 1 1 0 1 1 1 0
p = 4
y = 0 1 0 1 1 0 1 0 1 0 
n = 3

the 3 rightmost bits of y is 0 1 0 
it will replace x from bits 4 to bits 2 which is 1 1 1

Ответы [ 3 ]

1 голос
/ 09 января 2012

Я написал похожий:

 unsigned setbits (unsigned x, int p, int n, unsigned y)
{
  return (x & ~(~(~0<<n)<<(p+1-n)))|((y & ~(~0<<n))<<(p+1-n));
}
0 голосов
/ 03 июля 2018

Взгляните на следующий описательный код:

int setbitsKR(int x, int p, int n, int y){
    int shiftingDistance = p - n + 1,
        bitmask = (1 << n) - 1, // example, 11
        digitsOfY = (y & bitmask) << shiftingDistance, // whatever        
        bitmaskShiftedToLeft = bitmask << shiftingDistance, // 001100
        invertedBitmaskShiftedToLeft = ~bitmaskShiftedToLeft; // 110011

    // erase those middle bits of x
    x &= invertedBitmaskShiftedToLeft;

    // add those bits from y into x
    x |= digitsOfY;

    return x;
}

Короче говоря, он создает битовую маску (строку 1 s), сдвигает их, чтобы получить среднюю позицию x,обнуляет эти биты x с помощью & с помощью строки 0 с (инвертированная битовая маска) и, наконец, | с этой позиции с правильными цифрами y.

0 голосов
/ 18 июля 2011

Есть два разумных подхода.

Один из них ваш: возьмите младшие n битов y, обнулите средние n биты x и "или" вставьте их на место.

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

Я думаю, что мне действительно больше нравится ваша версия, потому что я уверен, что n и p с большей вероятностью будут константами времени компиляции, чем x и y. Таким образом, ваш ответ становится двумя маскирующими операциями с константами и одной "или"; Я сомневаюсь, что у тебя все получится лучше.

Я мог бы немного изменить его, чтобы было легче читать:

mask = (~0 << p | ~(~0 << (p-n+1)))
result = (mask & a) | (~mask & (y << (p-n+1)))

... но это та же скорость (действительно, код), что и у вас, когда mask является константой, и, возможно, медленнее, если mask является переменной.

Наконец, убедитесь, что у вас есть веская причина для беспокойства об этом. Чистый код - это хорошо, но для чего-то такого короткого, поместите его в хорошо документированную функцию, и это не имеет большого значения. Быстрый код - это хорошо, но не пытайтесь микрооптимизировать что-то подобное, пока ваш профилировщик не скажет вам об этом. (Современные процессоры делают это очень быстро; маловероятно, что производительность вашего приложения будет ограничена такого рода функциями. По крайней мере, это «невиновно, пока не доказана вина».)

...