Reputation: 231
I am learning C and I am still a very beginner.
My problem is the following. I have one unisgned int x and one unsigned int y. I would like to copy n bits from position p from x to the same position on y. I found some similar problems but not in C and most of the time the problem is slightly different if one takes the most right or left bits. I would also like to find a solution not depending on integer representation on the machine.
Here is what I did
unsigned fix_bits(unsigned x, unsigned y, int n, int p)
{
unsigned u1,u2,u3,u4,x1,y1,yf;
u1 = ~0; /*vector of 1*/
u2 = (u1>>n); /*0 from 0 to n-1 and 1s*/
u3 = ~(u2);/*1 from 0 to n-1 and 0s*/
u4 = u3>>p;/*0 from 0 to p-1, n 1 from p to p+n+1 and 0s*/
x1 = (x & u4);/*only keep n bits of x from position p*/
y1 = (y | u4);/*set y bit from p to (p+n+1) to 1, rest remains unchanged (0 | bit = bit)*/
yf = (x1 | y1);
return yf;
}
But it does not work:
The result of placing 2 bits at position 3 of 28 to 32 is 402653216
Does someone knows what am I doing wrong ?
Thank you very much
Upvotes: 2
Views: 3593
Reputation: 103
unsigned char
copy_Nbits(unsigned char num_S, unsigned char num_D, char start_off, char end_off)
{
unsigned char u1 = 0;
unsigned char u2 = 0;
u1 = ~u1;
u1 = (u1 >> ((8 * sizeof(num_S)) - 1 - end_off + start_off));
u1 = (u1 << start_off);
u2 = u1;
u2 &= num_S;
u1 = ~u1;
u1 &= num_D;
return (u1 | u2);
}
Upvotes: 0
Reputation: 23208
Regarding the problem: copy n bits from position p from x to the same position on y
Results with your code just as it is in the OP :
unsigned int x = 0xffffffff;
unsigned int y = 0x00000000;
unsigned int z = 0x00000000;
z = fix_bits(x, y, 5, 5);
It looks like you are operating from the wrong end of the target number. Change your logic to work from the right (LSB), instead of the left (MSB).
Try this:
unsigned fix_bits(unsigned x, unsigned y, int n, int p)
{
unsigned a, b, c, d, e;
int mask;
//Get mask
mask = ((1<<(n))-1)<<(p-n); //[edit] corrected, was ...<<p, is ...<<(p-n)
//apply mask to destination,
//XOR that with repositioned, BITwise NOTed source and apply mask
/*so you can do these steps:
a = mask|y;
b = ~x;
c = b<<p;
d = c&mask;
e = d^a;
return e;*/
//or do this one:
return ((mask&(~x<<p))^(mask|y)); //same thing
}
For the shown inputs, the example output is below:
unsigned int x = 0xffffffff;
unsigned int y = 0xf0000000;
unsigned int z = 0x00000000;
z = fix_bits(x, y, 3, 20);
Results after correction to mask (was <<p
, is <<(p-n)
):
Upvotes: 2
Reputation: 43
I needed a similar function for building an NES emulator. Using the solution by @ryyker, I created a slightly more general function for uint16_t
. It could probably be optimized. It should also meet the original poster's requirements when source_pos = dest_pos
.
Perhaps someone brought here while looking to solve the general case will find this helpful.
/*
* This was fun to figure out. Copy num bits at source_pos from source
* into dest at dest_pos. Positions start at 0, the LSB.
*/
uint16_t set_bits(uint16_t source, uint16_t dest, int num, int source_pos, int dest_pos)
{
unsigned long mask = ((1UL<<(num))-1UL)<<(source_pos);
if (dest_pos >= source_pos) {
return (dest & (~(mask << dest_pos))) | ((source & mask) << dest_pos);
}
return (dest & (~(mask >> (source_pos - dest_pos)))) | ((source & mask) >> (source_pos - dest_pos));
}
Upvotes: 0
Reputation: 231
So my final working solution is just
unsigned fix_bits(unsigned x, unsigned y, int n, int p)
{
unsigned u1,u2,u3,u4,x1,y1,yf;
u1 = ~0; /*vector of 1*/
u2 = (u1<<n); /*0 from 0 to n-1 and 1s*/
u3 = ~(u2);/*1 from 0 to n-1 and 0s*/
u4 = u3<<p;/*0 from 0 to p-1, n 1 from p to p+n+1 and 0s*/
x1 = (x & u4);/*only keep n bits of x from position p*/
y1 = (y | u4);/*set y bit from p to (p+n+1) to 1, rest remains unchanged (0 | bit = bit)*/
yf = (x1 | y1);
return yf;
}
And then
x = 28 = [0 0 ... 0 1 1 1 0]
y = 32 = [0 0 ... 1 0 0 0 0]
fix_bits(28,32,2,3) /placing two bits at position 3 from 28 to 32/
Outputs
z = 56 = [0 0 ... 1 1 1 0 0]
Upvotes: 0
Reputation: 7390
You're getting the mask wrong. Try:
unsigned mask = ((1 << n) - 1) << p;
return (y & ~mask) | (x & mask);
Upvotes: 2