C で 1 回の操作で 2 ビットを交換しますか?
-
13-09-2019 - |
質問
6 つの未知の値を含むバイトがあるとします。
???1?0??
ビット 2 と 4 を交換したいのですが (それなし いずれかを変更する ?
値):
???0?1??
しかし、これをどのように行うか ワンオペレーション Cで?
この操作はマイクロコントローラー上で 1 秒あたり数千回実行されるため、パフォーマンスが最優先されます。
これらのビットを「切り替える」のは問題ありません。これはビットを交換するのと同じではありませんが、切り替えは私の目的にはうまく機能します。
解決
試します:
x ^= 0x14;
の両方のビットをトグルします。それはあなたの最初の言及スワップとして質問に少し不明だし、その後、トグル例を与えます。とにかく、ビットを交換します。
x = precomputed_lookup [x];
precomputed_lookupが256バイト配列であり、最速の方法かもしれない、それはプロセッサ速度に対するメモリの速度に依存します。そうでなければ、それはです。
x = (x & ~0x14) | ((x & 0x10) >> 2) | ((x & 0x04) << 2);
編集:ビットをトグルに関するいくつかの詳細は、
。 あなたが一緒に(^
)2つの整数値をXORする場合、、XORは、このような、ビットレベルで実行されます。
for each (bit in value 1 and value 2)
result bit = value 1 bit xor value 2 bit
最初の値のビット0がそのように第二値、ビット1とビット1とビット0とXORされているように。 XOR演算は、値の他のビットは影響を受けません。実際には、それは多くのビットのパラレルビットXORです。
XORの真理値表を見ると、あなたはそれが値を持つビットをXORし表示されます「1」効果的にビットをトグルます。
a b a^b
0 0 0
0 1 1
1 0 1
1 1 0
だから、ビット1と3を切り替えるには、あなたは少し切り替えたい1、あなたが変わらない値を残したいゼロで2進数を記述します:
00001010
進に変換:0x0Aを。あなたが必要な数のビットを切り替えることができます:
0x39 = 00111001
トグルするビット0、3、4および5
他のヒント
これは、ビットあいを使用して1つの命令で「スワップ」の2つのビット(すなわちビットが場所を変更しない値)できません。
あなたが実際にそれらを交換したい場合に最適なアプローチはおそらく、ルックアップテーブルです。これは、多くの「厄介な」変換にも当てはまります。
BYTE lookup[256] = {/* left this to your imagination */};
for (/*all my data values */)
newValue = lookup[oldValue];
次のメソッドは単一の C 命令ではなく、単なる別のビットいじりメソッドです。方法は以下から簡略化されました XOR を使用した個々のビットの交換.
に記載されているように、 ロディの答え, 、ルックアップテーブルが最適です。これは、使いたくない場合にのみお勧めします。これは実際に、単に切り替えるだけでなく、ビットも交換します (つまり、ビット 2 にあるものはすべて 4 に含まれ、その逆も同様です)。
- b:元の値 - ???1?0??例えば
- バツ:ただの一時的なもの
r:結果
x = ((b >> 2) ^ (b >> 4)) & 0x01
r = b ^ ((x << 2) | (x << 4))
簡単な説明:調べたい 2 つのビットを取得して XOR し、値を次の場所に保存します。 x
. 。この値をビット 2 と 4 にシフトして戻す (そして一緒に OR 演算する) と、次のように XOR 演算して戻されたマスクが得られます。 b
元の 2 つのビットを交換します。以下の表は、考えられるすべてのケースを示しています。
bit2: 0 1 0 1
bit4: 0 0 1 1
x : 0 1 1 0 <-- Low bit of x only in this case
r2 : 0 0 1 1
r4 : 0 1 0 1
これを完全にテストしたわけではありませんが、すぐに試したいくつかのケースではうまくいくようでした。
これは、最適化されないことがありますが、それは動作するはずます:
unsigned char bit_swap(unsigned char n, unsigned char pos1, unsigned char pos2)
{
unsigned char mask1 = 0x01 << pos1;
unsigned char mask2 = 0x01 << pos2;
if ( !((n & mask1) != (n & mask2)) )
n ^= (mask1 | mask2);
return n;
}
以下の機能が(その結果スワッピングが単一の操作になる)必要に応じて、ルックアップテーブルを事前計算するためにこれを使用することができビット2および4を交換します。
unsigned char swap24(unsigned char bytein) {
unsigned char mask2 = ( bytein & 0x04 ) << 2;
unsigned char mask4 = ( bytein & 0x10 ) >> 2;
unsigned char mask = mask2 | mask4 ;
return ( bytein & 0xeb ) | mask;
}
私はそれをより明確にするために別の行に各操作を書いています。
あなたの価値があると言うのxすなわち、X = ??? 1?0 ??
2ビットは、この操作によって切り替えることができます:
x = x ^ ((1<<2) | (1<<4));
#include<stdio.h>
void printb(char x) {
int i;
for(i =7;i>=0;i--)
printf("%d",(1 & (x >> i)));
printf("\n");
}
int swapb(char c, int p, int q) {
if( !((c & (1 << p)) >> p) ^ ((c & (1 << q)) >> q) )
printf("bits are not same will not be swaped\n");
else {
c = c ^ (1 << p);
c = c ^ (1 << q);
}
return c;
}
int main()
{
char c = 10;
printb(c);
c = swapb(c, 3, 1);
printb(c);
return 0;
}
void swap_bits(uint32_t& n, int a, int b) {
bool r = (n & (1 << a)) != 0;
bool s = (n & (1 << b)) != 0;
if(r != s) {
if(r) {
n |= (1 << b);
n &= ~(1 << a);
}
else {
n &= ~(1 << b);
n |= (1 << a);
}
}
}
n
は交換する整数です。 a
そして b
は、スワップするビットの位置 (インデックス) であり、下位ビットから数えて 0 から始まります。
あなたの例を使用すると(n = ???1?0??
)、次のように関数を呼び出します。
swap_bits(n, 2, 4);
理論的根拠:ビットが異なる場合にのみビットを交換する必要があります (これが理由です) r != s
)。この場合、一方は 1、もう一方は 0 です。その後、実行したいのは 1 つだけであることに注意してください ビットセット 操作と1つ 少しはっきりした 手術。