6 つの未知の値を持つバイトがあるとします。
???1?0??
ビット 2 と 4 を交換したい (値を変更せず?
に):
???0?1??
しかし、Cで1 回の操作でこれを行うにはどうすればよいでしょうか。
私はこの操作をマイクロコントローラーで毎秒何千回も実行しているため、パフォーマンスが最優先事項です。
これらのビットを「トグル」しても問題ありません。これはビットを交換することと同じではありませんが、トグルは私の目的には問題なく機能します。
6 つの未知の値を持つバイトがあるとします。
???1?0??
ビット 2 と 4 を交換したい (値を変更せず?
に):
???0?1??
しかし、Cで1 回の操作でこれを行うにはどうすればよいでしょうか。
私はこの操作をマイクロコントローラーで毎秒何千回も実行しているため、パフォーマンスが最優先事項です。
これらのビットを「トグル」しても問題ありません。これはビットを交換することと同じではありませんが、トグルは私の目的には問題なく機能します。
Try:
x ^= 0x14;
That toggles both bits. It's a little bit unclear in question as you first mention swap and then give a toggle example. Anyway, to swap the bits:
x = precomputed_lookup [x];
where precomputed_lookup is a 256 byte array, could be the fastest way, it depends on the memory speed relative to the processor speed. Otherwise, it's:
x = (x & ~0x14) | ((x & 0x10) >> 2) | ((x & 0x04) << 2);
EDIT: Some more information about toggling bits.
When you xor (^
) two integer values together, the xor is performed at the bit level, like this:
for each (bit in value 1 and value 2)
result bit = value 1 bit xor value 2 bit
so that bit 0 of the first value is xor'ed with bit 0 of the second value, bit 1 with bit 1 and so on. The xor operation doesn't affect the other bits in the value. In effect, it's a parallel bit xor on many bits.
Looking at the truth table for xor, you will see that xor'ing a bit with the value '1' effectively toggles the bit.
a b a^b
0 0 0
0 1 1
1 0 1
1 1 0
So, to toggle bits 1 and 3, write a binary number with a one where you want the bit to toggle and a zero where you want to leave the value unchanged:
00001010
convert to hex: 0x0a. You can toggle as many bits as you want:
0x39 = 00111001
will toggle bits 0, 3, 4 and 5
ビットをいじることを使用して、1つの命令で2つのビットを「交換」することはできません(つまり、ビットは値ではなく場所を変更します)。
それらを実際に交換したい場合の最適なアプローチは、おそらくルックアップテーブルです。これは、多くの「厄介な」変換に当てはまります。
BYTE lookup[256] = {/* left this to your imagination */};
for (/*all my data values */)
newValue = lookup[oldValue];
次のメソッドは、単一の C 命令ではありません。これは、別のちょっとした操作方法です。この方法は、 XOR を使用して個々のビットを交換することから簡略化されました。
Roddy's answerで述べたように、ルックアップ テーブルが最適です。使用したくない場合にのみ、これをお勧めします。これは実際にトグルだけでなくビットもスワップします (つまり、ビット 2 にあるものはすべて 4 になり、その逆も同様です)。
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 をスワップします。これを使用して、必要に応じてルックアップ テーブルを事前計算できます (スワップが 1 回の操作になるように)。
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
ビットの位置 (インデックス) で、下位ビットから数えてゼロから始まります。
例 ( n = ???1?0??
) を使用すると、次のように関数を呼び出すことができます。
swap_bits(n, 2, 4);
根拠:ビットが異なる場合にのみビットを交換する必要があります(それが理由r != s
です)。この場合、そのうちの 1 つが 1 で、もう 1 つが 0 です。その後、1 つのビット セット操作と 1 つのビット クリア操作を実行する必要があることに注意してください。