I was wondering what the most effective formula, for testing if three numbers are a pythagorean triple is.
Just as a reminder: a pythagorean triple are three integers where a²+b²=c².
I mean not the most effective formula in terms of time, but a formula that is the most efficient in terms of not causing an overflow on a specific integer(lets say 32-bit unsigned int).
I was trying a bit with rearrangements of a*a + b*b == c*c:
Let's assume a<=b<c, then the best formula I could get to is:
2b*(c-b) == (a+b-c) * (a-b+c)
with this formula can be proven, that the right side is smaller than a*c and so should be the left side, but a*c doesn't look like a huge improvement of c*c.
So my question is, if there is a better formula for this conditional that works with bigger numbers without overflowing an integer space. The execution time of the formula doesn't matter that much, besides it should be O(1).
PS: I don't know if I should post such a question here or on Mathematics SE, but to me it seems to be more about programming.
EDIT If you need to have 32bit integers all the way down then you can just modify the math to fit your requirement. To keep it simple I do the math (squaring and summing) on 16bit chunks of data and use a struct that contains 2 unsigned ints as the result.
http://ideone.com/er2TaS
#include <iostream>
using namespace std;
struct u64 {
unsigned int lo;
unsigned int hi;
bool of;
};
u64 square(unsigned int a) {
u64 result;
unsigned int alo = (a & 0xffff);
unsigned int ahi = (a >> 16);
unsigned int aalo = alo * alo;
unsigned int aami = alo * ahi;
unsigned int aahi = ahi * ahi;
unsigned int aa1 = aalo & 0xffff;
unsigned int aa2 = (aalo >> 16) + (aami & 0xffff) + (aami & 0xffff);
unsigned int aa3 = (aa2 >> 16) + (aami >> 16) + (aami >> 16) + (aahi & 0xffff);
unsigned int aa4 = (aa3 >> 16) + (aahi >> 16);
result.lo = (aa1 & 0xffff) | ((aa2 & 0xffff) << 16);
result.hi = (aa3 & 0xffff) | (aa4 << 16);
result.of = false; // 0xffffffff^2 can't overflow
return result;
}
u64 sum(u64 a, u64 b) {
u64 result;
unsigned int a1 = a.lo & 0xffff;
unsigned int a2 = a.lo >> 16;
unsigned int a3 = a.hi & 0xffff;
unsigned int a4 = a.hi >> 16;
unsigned int b1 = b.lo & 0xffff;
unsigned int b2 = b.lo >> 16;
unsigned int b3 = b.hi & 0xffff;
unsigned int b4 = b.hi >> 16;
unsigned int s1 = a1 + b1;
unsigned int s2 = a2 + b2 + (s1 >> 16);
unsigned int s3 = a3 + b3 + (s2 >> 16);
unsigned int s4 = a4 + b4 + (s3 >> 16);
result.lo = (s1 & 0xffff) | ((s2 & 0xffff) << 16);
result.hi = (s3 & 0xffff) | ((s4 & 0xffff) << 16);
result.of = (s4 > 0xffff ? true : false);
return result;
}
bool isTriple(unsigned int a, unsigned int b, unsigned int c) {
u64 aa = square(a);
u64 bb = square(b);
u64 cc = square(c);
u64 aabb = sum(aa, bb);
return aabb.lo == cc.lo && aabb.hi == cc.hi && aabb.of == false;
}
int main() {
cout << isTriple(3,4,5) << endl;
cout << isTriple(2800,9600,10000) << endl;
return 0;
}
Conerting your 32bit integers to 64bit longs or even floating point doubles would edit reduce the chance of overflow and continue being, programmatically, O(1) since all the major architectures (x86, ARM, etc) have int to double conversion op codes at the low level and casting up to a long from int is also an O(1) operation.
bool isTriple(int a, int b, int c) {
long long bigA = a;
long long bigB = b;
long long bigC = c;
return bigA * bigA + bigB * bigB == bigC * bigC;
}
I think little rearrangement would help a lot.
a²+b²=c²
can be written as b²=c²-a²
which is b² = (c-a)(c+a)
and hence we arrive at
b/(c+a) = (c-a)/b
or (c+a)/b = b/(c-a)
Now using the above equation, you do not need to compute squares.
So we must do this
if(((c+a)/(double)b)==((double)(b)/(c-a)))
printf("Yes it is pythagorean triples");
else printf("No it is not");
I just want to ask if my method is correct to convert from little endian to big endian, just to make sure if I understand the difference.
I have a number which is stored in little-endian, here are the binary and hex representations of the number:
0001 0010 0011 0100 0101 0110 0111 1000
12345678
In big-endian format I believe the bytes should be swapped, like this:
1000 0111 0110 0101 0100 0011 0010 0001
87654321
Is this correct?
Also, the code below attempts to do this but fails. Is there anything obviously wrong or can I optimize something? If the code is bad for this conversion can you please explain why and show a better method of performing the same conversion?
uint32_t num = 0x12345678;
uint32_t b0,b1,b2,b3,b4,b5,b6,b7;
uint32_t res = 0;
b0 = (num & 0xf) << 28;
b1 = (num & 0xf0) << 24;
b2 = (num & 0xf00) << 20;
b3 = (num & 0xf000) << 16;
b4 = (num & 0xf0000) << 12;
b5 = (num & 0xf00000) << 8;
b6 = (num & 0xf000000) << 4;
b7 = (num & 0xf0000000) << 4;
res = b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7;
printf("%d\n", res);
OP's sample code is incorrect.
Endian conversion works at the bit and 8-bit byte level. Most endian issues deal with the byte level. OP's code is doing a endian change at the 4-bit nibble level. Recommend instead:
// Swap endian (big to little) or (little to big)
uint32_t num = 9;
uint32_t b0,b1,b2,b3;
uint32_t res;
b0 = (num & 0x000000ff) << 24u;
b1 = (num & 0x0000ff00) << 8u;
b2 = (num & 0x00ff0000) >> 8u;
b3 = (num & 0xff000000) >> 24u;
res = b0 | b1 | b2 | b3;
printf("%" PRIX32 "\n", res);
If performance is truly important, the particular processor would need to be known. Otherwise, leave it to the compiler.
[Edit] OP added a comment that changes things.
"32bit numerical value represented by the hexadecimal representation (st uv wx yz) shall be recorded in a four-byte field as (st uv wx yz)."
It appears in this case, the endian of the 32-bit number is unknown and the result needs to be store in memory in little endian order.
uint32_t num = 9;
uint8_t b[4];
b[0] = (uint8_t) (num >> 0u);
b[1] = (uint8_t) (num >> 8u);
b[2] = (uint8_t) (num >> 16u);
b[3] = (uint8_t) (num >> 24u);
[2016 Edit] Simplification
... The type of the result is that of the promoted left operand.... Bitwise shift operators C11 §6.5.7 3
Using a u after the shift constants (right operands) results in the same as without it.
b3 = (num & 0xff000000) >> 24u;
b[3] = (uint8_t) (num >> 24u);
// same as
b3 = (num & 0xff000000) >> 24;
b[3] = (uint8_t) (num >> 24);
Sorry, my answer is a bit too late, but it seems nobody mentioned built-in functions to reverse byte order, which in very important in terms of performance.
Most of the modern processors are little-endian, while all network protocols are big-endian. That is history and more on that you can find on Wikipedia. But that means our processors convert between little- and big-endian millions of times while we browse the Internet.
That is why most architectures have a dedicated processor instructions to facilitate this task. For x86 architectures there is BSWAP instruction, and for ARMs there is REV. This is the most efficient way to reverse byte order.
To avoid assembly in our C code, we can use built-ins instead. For GCC there is __builtin_bswap32() function and for Visual C++ there is _byteswap_ulong(). Those function will generate just one processor instruction on most architectures.
Here is an example:
#include <stdio.h>
#include <inttypes.h>
int main()
{
uint32_t le = 0x12345678;
uint32_t be = __builtin_bswap32(le);
printf("Little-endian: 0x%" PRIx32 "\n", le);
printf("Big-endian: 0x%" PRIx32 "\n", be);
return 0;
}
Here is the output it produces:
Little-endian: 0x12345678
Big-endian: 0x78563412
And here is the disassembly (without optimization, i.e. -O0):
uint32_t be = __builtin_bswap32(le);
0x0000000000400535 <+15>: mov -0x8(%rbp),%eax
0x0000000000400538 <+18>: bswap %eax
0x000000000040053a <+20>: mov %eax,-0x4(%rbp)
There is just one BSWAP instruction indeed.
So, if we do care about the performance, we should use those built-in functions instead of any other method of byte reversing. Just my 2 cents.
I think you can use function htonl(). Network byte order is big endian.
"I swap each bytes right?" -> yes, to convert between little and big endian, you just give the bytes the opposite order.
But at first realize few things:
size of uint32_t is 32bits, which is 4 bytes, which is 8 HEX digits
mask 0xf retrieves the 4 least significant bits, to retrieve 8 bits, you need 0xff
so in case you want to swap the order of 4 bytes with that kind of masks, you could:
uint32_t res = 0;
b0 = (num & 0xff) << 24; ; least significant to most significant
b1 = (num & 0xff00) << 8; ; 2nd least sig. to 2nd most sig.
b2 = (num & 0xff0000) >> 8; ; 2nd most sig. to 2nd least sig.
b3 = (num & 0xff000000) >> 24; ; most sig. to least sig.
res = b0 | b1 | b2 | b3 ;
You could do this:
int x = 0x12345678;
x = ( x >> 24 ) | (( x << 8) & 0x00ff0000 )| ((x >> 8) & 0x0000ff00) | ( x << 24) ;
printf("value = %x", x); // x will be printed as 0x78563412
One slightly different way of tackling this that can sometimes be useful is to have a union of the sixteen or thirty-two bit value and an array of chars. I've just been doing this when getting serial messages that come in with big endian order, yet am working on a little endian micro.
union MessageLengthUnion
{
uint16_t asInt;
uint8_t asChars[2];
};
Then when I get the messages in I put the first received uint8 in .asChars[1], the second in .asChars[0] then I access it as the .asInt part of the union in the rest of my program.
If you have a thirty-two bit value to store you can have the array four long.
I am assuming you are on linux
Include "byteswap.h" & Use int32_t bswap_32(int32_t argument);
It is logical view, In actual see, /usr/include/byteswap.h
one more suggestion :
unsigned int a = 0xABCDEF23;
a = ((a&(0x0000FFFF)) << 16) | ((a&(0xFFFF0000)) >> 16);
a = ((a&(0x00FF00FF)) << 8) | ((a&(0xFF00FF00)) >>8);
printf("%0x\n",a);
A Simple C program to convert from little to big
#include <stdio.h>
int main() {
unsigned int little=0x1234ABCD,big=0;
unsigned char tmp=0,l;
printf(" Little endian little=%x\n",little);
for(l=0;l < 4;l++)
{
tmp=0;
tmp = little | tmp;
big = tmp | (big << 8);
little = little >> 8;
}
printf(" Big endian big=%x\n",big);
return 0;
}
OP's code is incorrect for the following reasons:
The swaps are being performed on a nibble (4-bit) boundary, instead of a byte (8-bit) boundary.
The shift-left << operations of the final four swaps are incorrect, they should be shift-right >> operations and their shift values would also need to be corrected.
The use of intermediary storage is unnecessary, and the code can therefore be rewritten to be more concise/recognizable. In doing so, some compilers will be able to better-optimize the code by recognizing the oft-used pattern.
Consider the following code, which efficiently converts an unsigned value:
// Swap endian (big to little) or (little to big)
uint32_t num = 0x12345678;
uint32_t res =
((num & 0x000000FF) << 24) |
((num & 0x0000FF00) << 8) |
((num & 0x00FF0000) >> 8) |
((num & 0xFF000000) >> 24);
printf("%0x\n", res);
The result is represented here in both binary and hex, notice how the bytes have swapped:
0111 1000 0101 0110 0011 0100 0001 0010
78563412
Optimizing
In terms of performance, leave it to the compiler to optimize your code when possible. You should avoid unnecessary data structures like arrays for simple algorithms like this, doing so will usually cause different instruction behavior such as accessing RAM instead of using CPU registers.
#include <stdio.h>
#include <inttypes.h>
uint32_t le_to_be(uint32_t num) {
uint8_t b[4] = {0};
*(uint32_t*)b = num;
uint8_t tmp = 0;
tmp = b[0];
b[0] = b[3];
b[3] = tmp;
tmp = b[1];
b[1] = b[2];
b[2] = tmp;
return *(uint32_t*)b;
}
int main()
{
printf("big endian value is %x\n", le_to_be(0xabcdef98));
return 0;
}
You can use the lib functions. They boil down to assembly, but if you are open to alternate implementations in C, here they are (assuming int is 32-bits) :
void byte_swap16(unsigned short int *pVal16) {
//#define method_one 1
// #define method_two 1
#define method_three 1
#ifdef method_one
unsigned char *pByte;
pByte = (unsigned char *) pVal16;
*pVal16 = (pByte[0] << 8) | pByte[1];
#endif
#ifdef method_two
unsigned char *pByte0;
unsigned char *pByte1;
pByte0 = (unsigned char *) pVal16;
pByte1 = pByte0 + 1;
*pByte0 = *pByte0 ^ *pByte1;
*pByte1 = *pByte0 ^ *pByte1;
*pByte0 = *pByte0 ^ *pByte1;
#endif
#ifdef method_three
unsigned char *pByte;
pByte = (unsigned char *) pVal16;
pByte[0] = pByte[0] ^ pByte[1];
pByte[1] = pByte[0] ^ pByte[1];
pByte[0] = pByte[0] ^ pByte[1];
#endif
}
void byte_swap32(unsigned int *pVal32) {
#ifdef method_one
unsigned char *pByte;
// 0x1234 5678 --> 0x7856 3412
pByte = (unsigned char *) pVal32;
*pVal32 = ( pByte[0] << 24 ) | (pByte[1] << 16) | (pByte[2] << 8) | ( pByte[3] );
#endif
#if defined(method_two) || defined (method_three)
unsigned char *pByte;
pByte = (unsigned char *) pVal32;
// move lsb to msb
pByte[0] = pByte[0] ^ pByte[3];
pByte[3] = pByte[0] ^ pByte[3];
pByte[0] = pByte[0] ^ pByte[3];
// move lsb to msb
pByte[1] = pByte[1] ^ pByte[2];
pByte[2] = pByte[1] ^ pByte[2];
pByte[1] = pByte[1] ^ pByte[2];
#endif
}
And the usage is performed like so:
unsigned short int u16Val = 0x1234;
byte_swap16(&u16Val);
unsigned int u32Val = 0x12345678;
byte_swap32(&u32Val);
Below is an other approach that was useful for me
convertLittleEndianByteArrayToBigEndianByteArray (byte littlendianByte[], byte bigEndianByte[], int ArraySize){
int i =0;
for(i =0;i<ArraySize;i++){
bigEndianByte[i] = (littlendianByte[ArraySize-i-1] << 7 & 0x80) | (littlendianByte[ArraySize-i-1] << 5 & 0x40) |
(littlendianByte[ArraySize-i-1] << 3 & 0x20) | (littlendianByte[ArraySize-i-1] << 1 & 0x10) |
(littlendianByte[ArraySize-i-1] >>1 & 0x08) | (littlendianByte[ArraySize-i-1] >> 3 & 0x04) |
(littlendianByte[ArraySize-i-1] >>5 & 0x02) | (littlendianByte[ArraySize-i-1] >> 7 & 0x01) ;
}
}
Below program produce the result as needed:
#include <stdio.h>
unsigned int Little_To_Big_Endian(unsigned int num);
int main( )
{
int num = 0x11223344 ;
printf("\n Little_Endian = 0x%X\n",num);
printf("\n Big_Endian = 0x%X\n",Little_To_Big_Endian(num));
}
unsigned int Little_To_Big_Endian(unsigned int num)
{
return (((num >> 24) & 0x000000ff) | ((num >> 8) & 0x0000ff00) | ((num << 8) & 0x00ff0000) | ((num << 24) & 0xff000000));
}
And also below function can be used:
unsigned int Little_To_Big_Endian(unsigned int num)
{
return (((num & 0x000000ff) << 24) | ((num & 0x0000ff00) << 8 ) | ((num & 0x00ff0000) >> 8) | ((num & 0xff000000) >> 24 ));
}
#include<stdio.h>
int main(){
int var = 0X12345678;
var = ((0X000000FF & var)<<24)|
((0X0000FF00 & var)<<8) |
((0X00FF0000 & var)>>8) |
((0XFF000000 & var)>>24);
printf("%x",var);
}
Here is a little function I wrote that works pretty good, its probably not portable to every single machine or as fast a single cpu instruction, but should work for most. It can handle numbers up to 32 byte (256 bit) and works for both big and little endian swaps. The nicest part about this function is you can point it into a byte array coming off or going on the wire and swap the bytes inline before converting.
#include <stdio.h>
#include <string.h>
void byteSwap(char**,int);
int main() {
//32 bit
int test32 = 0x12345678;
printf("\n BigEndian = 0x%X\n",test32);
char* pTest32 = (char*) &test32;
//convert to little endian
byteSwap((char**)&pTest32, 4);
printf("\n LittleEndian = 0x%X\n", test32);
//64 bit
long int test64 = 0x1234567891234567LL;
printf("\n BigEndian = 0x%lx\n",test64);
char* pTest64 = (char*) &test64;
//convert to little endian
byteSwap((char**)&pTest64,8);
printf("\n LittleEndian = 0x%lx\n",test64);
//back to big endian
byteSwap((char**)&pTest64,8);
printf("\n BigEndian = 0x%lx\n",test64);
return 0;
}
void byteSwap(char** src,int size) {
int x = 0;
char b[32];
while(size-- >= 0) { b[x++] = (*src)[size]; };
memcpy(*src,&b,x);
}
output:
$gcc -o main *.c -lm
$main
BigEndian = 0x12345678
LittleEndian = 0x78563412
BigEndian = 0x1234567891234567
LittleEndian = 0x6745239178563412
BigEndian = 0x1234567891234567
I'm working on this programming project and part of it is to write a function with just bitwise operators that switches every two bits. I've come up with a comb sort of algorithm that accomplishes this but it only works for unsigned numbers, any ideas how I can get it to work with signed numbers as well? I'm completely stumped on this one. Heres what I have so far:
// Mask 1 - For odd bits
int a1 = 0xAA; a1 <<= 24;
int a2 = 0xAA; a2 <<= 16;
int a3 = 0xAA; a3 <<= 8;
int a4 = 0xAA;
int mask1 = a1 | a2 | a3 | a4;
// Mask 2 - For even bits
int b1 = 0x55; b1 <<= 24;
int b2 = 0x55; b2 <<= 16;
int b3 = 0x55; b3 <<= 8;
int b4 = 0x55;
int mask2 = b1 | b2 | b3 | b4;
// Mask Results
int odd = x & mask1;
int even = x & mask2;
int newNum = (odd >> 1) | (even << 1);
return newNum;
The manual creation of the masks by or'ing variables together is because the only constants that can be used are between 0x00-0xFF.
The problem is that odd >> 1 will sign extend with negative numbers. Simply do another and to eliminate the duplicated bit.
int newNum = ((odd >> 1) & mask2) | (even << 1);
Minimizing the operators and noticing the sign extension problem gives:
int odd = 0x55;
odd |= odd << 8;
odd |= odd << 16;
int newnum = ((x & odd) << 1 ) // This is (sort of well defined)
| ((x >> 1) & odd); // this handles the sign extension without
// additional & -operations
One remark though: bit twiddling should be generally applied to unsigned integers only.
When you right shift a signed number, the sign will also be extended. This is known as sign extension. Typically when you are dealing with bit shifting, you want to use unsigned numbers.
Minimizing use of constants by working one byte at a time:
unsigned char* byte_p;
unsigned char byte;
int ii;
byte_p = &x;
for(ii=0; ii<4; ii++) {
byte = *byte_p;
*byte_p = ((byte & 0xAA)>>1) | ((byte & 0x55) << 1);
byte_p++;
}
Minimizing operations and keeping constants between 0x00 and 0xFF:
unsigned int comb = (0xAA << 8) + 0xAA;
comb += comb<<16;
newNum = ((x & comb) >> 1) | ((x & (comb >> 1)) << 1);
10 operations.
Just saw the comments above and realize this is implementing (more or less) some of the suggestions that #akisuihkonen made. So consider this a tip of the hat!
I had this interview question -
Swap byte 2 and byte 4 within an integer sequence.
Integer is a 4 byte wide i.e. 32 bits
My approach was to use char *pointer and a temp char to swap the bytes.
For clarity I have broken the steps otherwise an character array can be considered.
unsigned char *b2, *b4, tmpc;
int n = 0xABCD; ///expected output 0xADCB
b2 = &n; b2++;
b4 = &n; b4 +=3;
///swap the values;
tmpc = *b2;
*b2 = *b4;
*b4 = tmpc;
Any other methods?
int someInt = 0x12345678;
int byte2 = someInt & 0x00FF0000;
int byte4 = someInt & 0x000000FF;
int newInt = (someInt & 0xFF00FF00) | (byte2 >> 16) | (byte4 << 16);
To avoid any concerns about sign extension:
int someInt = 0x12345678;
int newInt = (someInt & 0xFF00FF00) | ((someInt >> 16) & 0x000000FF) | ((someInt << 16) & 0x00FF0000);
(Or, to really impress them, you could use the triple XOR technique.)
Just for fun (probably a tupo somewhere):
int newInt = someInt ^ ((someInt >> 16) & 0x000000FF);
newInt = newInt ^ ((newInt << 16) & 0x00FF0000);
newInt = newInt ^ ((newInt >> 16) & 0x000000FF);
(Actually, I just tested it and it works!)
You can mask out the bytes you want and shift them around. Something like this:
unsigned int swap(unsigned int n) {
unsigned int b2 = (0x0000FF00 & n);
unsigned int b4 = (0xFF000000 & n);
n ^= b2 | b4; // Clear the second and fourth bytes
n |= (b2 << 16) | (b4 >> 16); // Swap and write them.
return n;
}
This assumes that the "first" byte is the lowest order byte (even if in memory it may be stored big-endian).
Also it uses unsigned ints everywhere to avoid right shifting introducing extra 1s due to sign extension.
What about unions?
int main(void)
{
char tmp;
union {int n; char ary[4]; } un;
un.n = 0xABCDEF00;
tmp = un.ary[3];
un.ary[3] = un.ary[1];
un.ary[1] = tmp;
printf("0x%.2X\n", un.n);
}
in > 0xABCDEF00
out>0xEFCDAB00
Please don't forget to check endianess. this only work for little endian, but should not be hard to make it portable.
Like this:
input: 10010011
(10->01->00->11)
output: 11000110
(11->00->01->10)
input: 11010001
(11->01->00->01)
output: 01000111
(01->00->01->11)
Anyone has any ideas about that?
Fewer operations than lserni's algorithm:
uint32_t reverseByTwo(uint32_t value) {
value = ((value & 0x03030303) << 2) | ((value >> 2) & 0x03030303); // swap adjacent pairs
value = ((value & 0x0F0F0F0F) << 4) | ((value >> 4) & 0x0F0F0F0F); // swap nibbles
value = ((value & 0x00FF00FF) << 8) | ((value >> 8) & 0x00FF00FF); // swap bytes
value = ((value & 0x0000FFFF) << 16) | ((value >> 16) & 0x0000FFFF);
return value;
}
For 64-bit values just add another swap for the 32-bit halves, for smaller types, just leave out the last few swaps.
Weird request. I'd do it like this:
uint32_t reverseByTwo(uint32_t value)
{
int i;
uint32_t new_value = 0;
for (i = 0; i < 16; i++)
{
new_value <<= 2;
new_value |= (value & 0x3);
value >>= 2;
}
return new_value;
}
At each iteration, the two LSB of value are placed in the two LSB of new_value, which is shifted to the left.
For an eight-bit value,
uint8_t reverseByTwo(uint8_t value)
{
int i;
uint32_t new_value = 0;
for (i = 0; i < 4; i++)
{
new_value <<= 2;
new_value |= (value & 0x3);
value >>= 2;
}
return new_value;
}
if performances are at a premium, you can manually unroll the loop (GCC should do this by itself, but sometimes doesn't bother) and declare the function as inline.
new_value = 0;
// new_value <<= 2; // First time not necessary
new_value |= (value & 0x3);
value >>= 2;
new_value <<= 2;
new_value |= (value & 0x3);
value >>= 2;
new_value <<= 2;
new_value |= (value & 0x3);
value >>= 2;
new_value <<= 2;
new_value |= (value & 0x3);
// value >>= 2;
return new_value;
The fastest possible way to transform the bits in a single byte (char) into another single byte is to build yourself an array:
unsigned char rev[256];
rev[0] = 0; /* 00000000 -> 00000000 */
...
rev[147] = 198; /* 10010011 -> 11000110 */
...
rev[198] = 147; /* 11000110 -> 10010011 */
...
rev[255] = 255; /* 11111111 -> 11111111 */
To convert a number x to its bit-reversed form, just write rev[x]. If you have multiple bytes to convert, such as in a 4-byte int, just look up the 4 bytes in the rev table.
You'll need to convert binary to another base (here, I use decimal) when writing this code, because C doesn't have binary constants (which would be ten times more useful than octal constants).
You could also put the values into the initializer, but you'll have to count positions to make sure everything is in the right place. (Maybe write a little program to do it!)
unsigned char rev[256] = {0, ..., 198, ..., 147, ..., 255};
Fill in the ... with all the other numbers in the right places.
$x = (($x & 0x33333333) << 2) | (($x & 0xCCCCCCCC) >> 2);
$x = (($x & 0x0F0F0F0F) << 4) | (($x & 0xFOFOFOFO) >> 4);
$x = (($x & 0x00FF00FF) << 8) | (($x & 0xFF00FF00) >> 8);
$x = (($x & 0x0000FFFF) << 16) | (($x & 0xFFFF0000) >> 16);
To give credit where due, this algorithm came from "Hacker's Delight" by Henry S. Warren, Jr. The only difference is that the algorithm in the book didn't reverse by pairs; it just reversed the bits.
#include <limits.h>
#define INT_BITS (sizeof(int) * CHAR_BIT)
unsigned reverse_bits(unsigned x) {
#define PAIR(i) ((((x) >> (i*2)) & 3) << (INT_BITS - (i+1)*2))
unsigned result = 0;
unsigned i;
for(i = 0; i < INT_BITS/2; i++) {
result |= PAIR(i);
}
return result;
}
Though this will do it for an unsigned int, whereas you might want to replace int and unsigned there with char and unsigned char.
If you want the fastest possible:
output =
((input & 0xc0) >> 6) |
((input & 0x30) >> 2) |
((input & 0xc) << 2) |
((input & 0x3) << 6);
You have bits (ab cd ef gh) and want (gh ef cd ab)
If you multiply by 0x101 and store in 16 bit int, you get (ab cd ef gh ab cd ef gh).
Then you have your bit pattern in that number in two group of four bits:
(00 00 ef 00 ab 00 00 00),
(00 00 00 gh 00 cd 00 00)
So you just have to shift and mask appropriately
unsigned char swap_bit_pairs(unsigned char b)
{
unsigned int a = 0x101*b;
return ((a >> 6) & 0x33) | ((a >> 2) & 0xCC);
}
So it's possible in 6 operations
EDIT: oups! I wrote 0x66 instead of 0xCC