2017-02-06 11 views
3

すべてのビットがストレッチマスクの4ビットを表すマスクをストレッチしたい。 私は++とSystemCの例えばストレッチマスクビット操作

Cを使用してストレッチするエレガントなビット操作を探しています:

入力:

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

「結果」には少なくとも32 * 4 = 128ビットのタイプが必要です大。 – izlin

+0

はい、私はあなたがベクトルを使用する変数型を作成することができると信じています – rodrigo

+1

私はsc_biguint <128>を持っているのでSystemCライブラリを使用しています。 3行目のカッコがありません。 –

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

ここですべてのビットが延伸マスクの4ビットを表す64ビットに16ビットマスクを延伸する方法は次のとおり

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ビットのマスクを使用します。それは、このような、トップ32ビットにマスクの上位8ビットを移動:

0000000000000000 0000000000000000 0000000000000000 ABCDEFGHIJKLMNOP 

0000000000000000 00000000ABCDEFGH 0000000000000000 00000000IJKLMNOP 

なり、それはの下8ビットからマスクを延伸する同様の問題を解決します32ビット・ワード、上部および下部32ビットに同時に:

000000000000ABCD 000000000000EFGH 000000000000IJKL 000000000000MNOP 

ビットが広がるされるまで、それはそうで16と内部4ビットのためにそれを行います。

000A000B000C000D 000E000F000G000H 000I000J000K000L 000M000N000O000P 

その後二回自分自身で結果をオアすることにより、4ビットの間で「汚れ」、それらを:

AAAABBBBCCCCDDDD EEEEFFFFGGGGHHHH IIIIJJJJKKKKLLLL MMMMNNNNOOOOPPPP 

あなたは48ビットでシフトする余分な最初のステップを追加することにより、128ビットにこれを拡張する可能性があり、 128ビット定数とマスク:あなたはまた、単にビットパターンを繰り返すことで、128ビットのうち他の定数を伸ばす必要があるだろう

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

。しかし(私が知る限り)C++で128ビットの定数を宣言する方法はありませんが、おそらくマクロなどでそれを行うことができます(see this question)。また、上下の16ビットで別々に64ビットバージョンを使用するだけで、128ビットバージョンを作成することもできます。

マスキング定数をロードすることは困難であるか、またはあなたがシフトとマスキング使用して、以前のものからそれぞれ1を生成することができますボトルネックが判明した場合:

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

最後の2つの命令 '(x | = x << 2; x | = x << 1)'を 'x * = 0xf'に置き換えることができます。 – MSalters

+0

マスクを組み合わせて組み合わせることもできます。つまり、 '(x * =(1 + 1ULL << 12 + 1ULL << 24 + 1ULL << 36)'で始めることができます。ビットが衝突する位置はいくつかありますが、とにかく – MSalters

1

他のソリューションが良いです。しかし、それらのほとんどはC++よりもCです。この解決策はかなり簡単です:std::bitsetを使用し、各入力ビットに4ビットを設定します。

#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!

x86で
0

64ビットワードの(例えば、各ニブルの低いビットへ)PDEPintrinsic正しいニブルに16個のマスクビットを移動するために使用することができ、そしてその後、シフト+のカップルを使用したり、単語の残りの部分にそれらを中傷する:

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

あなたはまた、これらの2つのORと同じSMEを達成0xFすることにより、単一の乗算によって、2つのシフトを置き換えることができます指輪。

最後に、SIMDアプローチを考えてみましょう。上記のsamgakのようなソリューションは、自然にSIMDにマップする必要があります。