for each bit in the data type:
rotate bit into carry flag
rotate carry flag into destination.
end-for
由于 C 和 C + + 不支持旋转进位和旋转从进位,所以用于此的高级语言代码要复杂得多。进行旗必须建模。
例如,编辑: 汇编语言
; Enter with value to reverse in R0.
; Assume 8 bits per byte and byte is the native processor type.
LODI, R2 8 ; Set up the bit counter
Loop:
RRC, R0 ; Rotate R0 right into the carry bit.
RLC, R1 ; Rotate R1 left, then append carry bit.
DJNZ, R2 Loop ; Decrement R2 and jump if non-zero to "loop"
LODR, R0 R1 ; Move result into R0.
((a & 0x1) << 7) //get first bit on the right and shift it into the first left position
| ((a & 0x2) << 5) //add it to the second bit and shift it into the second left position
//and so on
这是一个古老的问题,但似乎没有人显示出明确的容易的方式(最接近的是 edW)。我使用 C # 来测试这个,但是在这个例子中没有什么是不能在 C 中轻松完成的。
void PrintBinary(string prompt, int num, int pad = 8)
{
Debug.WriteLine($"{prompt}: {Convert.ToString(num, 2).PadLeft(pad, '0')}");
}
int ReverseBits(int num)
{
int result = 0;
int saveBits = num;
for (int i = 1; i <= 8; i++)
{
// Move the result one bit to the left
result = result << 1;
//PrintBinary("saveBits", saveBits);
// Extract the right-most bit
var nextBit = saveBits & 1;
//PrintBinary("nextBit", nextBit, 1);
// Add our extracted bit to the result
result = result | nextBit;
//PrintBinary("result", result);
// We're done with that bit, rotate it off the right
saveBits = saveBits >> 1;
//Debug.WriteLine("");
}
return result;
}
void PrintTest(int nextNumber)
{
var result = ReverseBits(nextNumber);
Debug.WriteLine("---------------------------------------");
PrintBinary("Original", nextNumber);
PrintBinary("Reverse", result);
}
void Main()
{
// Calculate the reverse for each number between 1 and 255
for (int x = 250; x < 256; x++)
PrintTest(x);
}
#define BITS_SIZE 8
int
reverseBits ( int a )
{
int rev = 0;
int i;
/* scans each bit of the input number*/
for ( i = 0; i < BITS_SIZE - 1; i++ )
{
/* checks if the bit is 1 */
if ( a & ( 1 << i ) )
{
/* shifts the bit 1, starting from the MSB to LSB
* to build the reverse number
*/
rev |= 1 << ( BITS_SIZE - 1 ) - i;
}
}
return rev;
}
#include <limits.h>
unsigned char reverse(unsigned char c) {
int shift;
unsigned char result = 0;
for (shift = 0; shift < CHAR_BIT; shift++) {
result <<= 1;
result |= c & 1;
c >>= 1;
}
return result;
}
#include <algorithm>
#include <bitset>
#include <exception>
#include <iostream>
#include <limits>
#include <string>
// helper lambda function template
template<typename T>
auto getBits = [](T value) {
return std::bitset<sizeof(T) * CHAR_BIT>{value};
};
// Function template to flip the bits
// This will work on integral types such as int, unsigned int,
// std::uint8_t, 16_t etc. I did not test this with floating
// point types. I chose to use the `bitset` here to convert
// from T to string as I find it easier to use than some of the
// string to type or type to string conversion functions,
// especially when the bitset has a function to return a string.
template<typename T>
T reverseBits(T& value) {
static constexpr std::uint16_t bit_count = sizeof(T) * CHAR_BIT;
// Do not use the helper function in this function!
auto bits = std::bitset<bit_count>{value};
auto str = bits.to_string();
std::reverse(str.begin(), str.end());
bits = std::bitset<bit_count>(str);
return static_cast<T>( bits.to_ullong() );
}
// main program
int main() {
try {
std::uint8_t value = 0xE0; // 1110 0000;
std::cout << +value << '\n'; // don't forget to promote unsigned char
// Here is where I use the helper function to display the bit pattern
auto bits = getBits<std::uint8_t>(value);
std::cout << bits.to_string() << '\n';
value = reverseBits(value);
std::cout << +value << '\n'; // + for integer promotion
// using helper function again...
bits = getBits<std::uint8_t>(value);
std::cout << bits.to_string() << '\n';
} catch(const std::exception& e) {
std::cerr << e.what();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
template <class T>
void print_binary(T n)
{ T mask = 1ULL << ((sizeof(n) * 8) - 1); // will set the most significant bit
for(; mask != 0; mask >>= 1) putchar('0' | !!(n & mask));
putchar('\n');
}
int main() {
uint32_t n = 12;
print_binary(n);
n = reverse_bits(n);
print_binary(n);
unsigned char c = 'a';
print_binary(c);
c = reverse_bits(c);
print_binary(c);
uint16_t s = 12;
print_binary(s);
s = reverse_bits(s);
print_binary(s);
uint64_t l = 12;
print_binary(l);
l = reverse_bits(l);
print_binary(l);
return 0;
}
反转,不稳定
最后但并非最不重要的是,如果最简单意味着更少的行,为什么不尝试内联汇编?
您可以通过在编译时添加 -masm=intel 来测试下面的代码片段:
unsigned char reverse_bits(unsigned char c) {
__asm__ __volatile__ (R"(
mov cx, 8
daloop:
ror di
adc ax, ax
dec cx
jnz short daloop
;)");
}
逐行解释:
mov cx, 8 ; we will reverse the 8 bits contained in one byte
daloop: ; while loop
shr di ; Shift Register `di` (containing value of the first argument of callee function) to the Right
rcl ax ; Rotate Carry Left: rotate ax left and add the carry from shr di, the carry is equal to 1 if one bit was "lost" from previous operation
dec cl ; Decrement cx
jnz short daloop; Jump if cx register is Not equal to Zero, else end loop and return value contained in ax register
// this is the only header used by the reverse_bits() function
#include <type_traits>
// these headers are only used by demonstration code
#include <string>
#include <iostream>
#include <cstdint>
template<typename T>
T reverse_bits( T n ) {
// we force the passed-in type to its unsigned equivalent, because C++ may
// perform arithmetic right shift instead of logical right shift, depending
// on the compiler implementation.
typedef typename std::make_unsigned<T>::type unsigned_T;
unsigned_T v = (unsigned_T)n;
// swap every bit with its neighbor
v = ((v & 0xAAAAAAAAAAAAAAAA) >> 1) | ((v & 0x5555555555555555) << 1);
// swap every pair of bits
v = ((v & 0xCCCCCCCCCCCCCCCC) >> 2) | ((v & 0x3333333333333333) << 2);
// swap every nybble
v = ((v & 0xF0F0F0F0F0F0F0F0) >> 4) | ((v & 0x0F0F0F0F0F0F0F0F) << 4);
// bail out if we've covered the word size already
if( sizeof(T) == 1 ) return v;
// swap every byte
v = ((v & 0xFF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF) << 8);
if( sizeof(T) == 2 ) return v;
// etc...
v = ((v & 0xFFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF) << 16);
if( sizeof(T) <= 4 ) return v;
v = ((v & 0xFFFFFFFF00000000) >> 32) | ((v & 0x00000000FFFFFFFF) << 32);
// explictly cast back to the original type just to be pedantic
return (T)v;
}
template<typename T>
std::string to_binary_str( T n ) {
const unsigned int bit_count = sizeof(T)*8;
char s[bit_count+1];
typedef typename std::make_unsigned<T>::type unsigned_T;
unsigned_T v = (unsigned_T)n;
for( int i = bit_count - 1; i >= 0; --i ) {
if( v & 1 )
s[i] = '1';
else
s[i] = '0';
v >>= 1;
}
s[bit_count] = 0; // string null terminator
return s;
}
int main() {
{
char x = 0xBA;
std::cout << to_binary_str( x ) << std::endl;
char y = reverse_bits( x );
std::cout << to_binary_str( y ) << std::endl;
}
{
short x = 0xAB94;
std::cout << to_binary_str( x ) << std::endl;
short y = reverse_bits( x );
std::cout << to_binary_str( y ) << std::endl;
}
{
uint64_t x = 0xFEDCBA9876543210;
std::cout << to_binary_str( x ) << std::endl;
uint64_t y = reverse_bits( x );
std::cout << to_binary_str( y ) << std::endl;
}
return 0;
}
(z is the input polynomial (or just any hex string)
xn = 0 ^ (x = length(z)); # initialize to numeric 0,
# foo^bar in awk means
# foo-to-bar-th-power.
# same as foo**bar in other langs
y = substr(_REF_bitREV_hex, 2); # by pre-trimming the lookup str,
# it allows skipping the + 1 at
# every cycle of the loop
do {
xn *= 16
xn += index(y, substr(z,x,1)) # keep in mind that this is awk syntax,
# where strings start at index-1, not zero.
} while ( 1 < x—- );