2017-02-06 7 views
3

Я хочу растянуть маску, в которой каждый бит представляет собой 4 бита растянутой маски. Ищу шикарном манипуляции с битами, чтобы растянуть с помощью C++ и SystemCstretch mask - bit манипуляция

, например:

вход:

mask (32 bits) = 0x0000CF00 

выход:

stretched mask (128 bits) = 0x00000000 00000000 FF00FFFF 00000000 

и просто уточнить в примере рассмотрим байт C:

0xC = 1100 after stretching: 1111111100000000 = 0xFF00 
+0

Разрешено ли '_pdep_u32'? – harold

+0

Вы хотите растянуть любое количество бит, например 17, 78, ... или вам нужны только кратные 16 или 32? – izlin

+0

кратные 32. –

ответ

3

Сделать это в элегантной форме непросто. Простой режим может быть, это создать цикл со сдвигом бита

sc_biguint<128> result = 0; 
for(int i = 0; i < 32; i++){ 
    if(bit_test(var, i)){ 
     result +=0x0F; 
    } 
    result << 4; 
} 
+0

Обратите внимание, что 'result' нужен тип, который не менее 32 * 4 = 128 бит большой. – izlin

+0

Да, я считаю, что вы можете создать переменный тип ou использовать вектор – rodrigo

+1

Я использую библиотеки SystemC, поэтому у меня есть sc_biguint <128>. отсутствующая скобка в третьей строке. –

1

ли эта работа для вас?

#include <stdio.h> 

long long Stretch4x(int input) 
{ 
    long long output = 0; 

    while (input & -input) 
    { 
     int b = (input & -input); 
     long long s = 0; 
     input &= ~b; 
     s = b*15; 
     while(b>>=1) 
     { 
      s <<= 3; 
     } 

     output |= s; 
    } 
    return output; 
} 

int main(void) { 
    int input = 0xCF00; 

    printf("0x%0x ==> 0x%0llx\n", input, Stretch4x(input)); 
    return 0; 
} 

Выход:

0xcf00 ==> 0xff00ffff00000000 
3

Вот способ растяжения 16-битовая маски в 64 бита, где каждый бит представляет 4 бит растянутой маски:

uint64_t x = 0x000000000000CF00LL; 

x = (x | (x << 24)) & 0x000000ff000000ffLL; 
x = (x | (x << 12)) & 0x000f000f000f000fLL; 
x = (x | (x << 6)) & 0x0303030303030303LL; 
x = (x | (x << 3)) & 0x1111111111111111LL; 
x |= x << 1; 
x |= x << 2; 

Она начинается с маской в ​​нижних 16 бит. Затем он перемещает верхние 8 бит маски в верхние 32 бит, как это:

0000000000000000 0000000000000000 0000000000000000 ABCDEFGHIJKLMNOP 

становится

0000000000000000 00000000ABCDEFGH 0000000000000000 00000000IJKLMNOP 

Затем он решает подобную проблему растяжения маску из нижних 8 бит 32-битное слово, к верхнему и нижнему 32-бит одновременно:

000000000000ABCD 000000000000EFGH 000000000000IJKL 000000000000MNOP 

Затем он делает это на 4 бита внутри 16 и так далее до тех пор, пока биты разложены:

000A000B000C000D 000E000F000G000H 000I000J000K000L 000M000N000O000P 

Затем он «мажет» их через 4 бита на ORing результат с собой дважды:

AAAABBBBCCCCDDDD EEEEFFFFGGGGHHHH IIIIJJJJKKKKLLLL MMMMNNNNOOOOPPPP 

Вы можете расширить это до 128 бит, добавляя дополнительный первый этап, на котором сдвиг на 48 бит и маска с 128-бит константой:

x = (x | (x << 48)) & 0x000000000000ffff000000000000ffffLLL; 

Вы бы также, чтобы растянуть другие константы из на 128 бит, просто повторяя битовые шаблоны. Однако (насколько я знаю) нет способа объявить 128-битную константу в C++, но, возможно, вы могли бы сделать это с помощью макросов или чего-то еще (see this question). Вы также можете сделать 128-битную версию, просто используя 64-разрядную версию в верхнем и нижнем 16 бит отдельно.

При загрузке константы маскирования оказывается трудности или узким местом вы можете создать каждый из предыдущего с помощью сдвига и маскирования:

uint64_t m = 0x000000ff000000ffLL; 

m &= m >> 4; m |= m << 16; // gives 0x000f000f000f000fLL 
m &= m >> 2; m |= m << 8; // gives 0x0303030303030303LL 
m &= m >> 1; m |= m << 4; // gives 0x1111111111111111LL 
+0

Последние две команды '(x | = x << 2; x | = x << 1)' могут быть заменены на 'x * = 0xf' – MSalters

+0

Похоже, что маски также могут быть объединены вместе. То есть вы можете начать с '(x * = (1 + 1ULL << 12 + 1ULL << 24 + 1ULL << 36)'. У вас будет несколько позиций, где бит сталкивается, но вы маскируете их так или иначе. – MSalters

1

Другие решения хороши. Однако большинство из них больше C, чем C++. Это решение довольно прямолинейно: оно использует std::bitset и устанавливает четыре бита для каждого входного бита.

#include <bitset> 
#include <iostream> 

std::bitset<128> 
starch_32 (const std::bitset<32> &input) 
{ 
    std::bitset<128> output; 

    for (size_t i = 0; i < input.size(); ++i) { 
     // If `input[N]` is `true`, set `output[N*4, N*4+4]` to true. 
     if (input.test (i)) { 
      const size_t output_index = i * 4; 

      output.set (output_index); 
      output.set (output_index + 1); 
      output.set (output_index + 2); 
      output.set (output_index + 3); 
     } 
    } 

    return output; 
} 

// Example with 0xC. 
int main() { 
    std::bitset<32> input{0b1100}; 

    auto result = starch_32 (input); 

    std::cout << "0x" << std::hex << result.to_ullong() << "\n"; 
} 

Try it online!

0

На x86 можно использовать PDEPintrinsic, чтобы переместить 16 бит маски в правильный полубайт (в младший бит каждого полубайта, например) из 64-битового слова, и затем использовать пару Shift + или намазать их в остальную части слова:

unsigned long x = _pdep_u64(m, 0x1111111111111111); 
x |= x << 1; 
x |= x << 2; 

Вы также мог бы заменить эти два OR и два сдвига по одной умножению на 0xF выполняющего тот же SME кольцо.

Наконец, вы можете рассмотреть подход SIMD: такие решения, как, например, samgak, должны отображаться естественным образом в SIMD.

 Смежные вопросы

  • Нет связанных вопросов^_^