Optimising bitwise operations in C - c

I had a problem in hand as this :
"Exercise 2-6. Write a function setbits(x,p,n,y) that returns x with the n bits that begin at
position p set to the rightmost n bits of y, leaving the other bits unchanged."
I've written a function for this as below. This is working as expected.
int func_setx(int x,int p,int n,int y)
{
int a_t= ~0 << (p+n);
int b_t= ~a_t >> n;
int x_t= x& (a_t | b_t); // a temporary x which has the bits to be changed as 0 , rest of the bits unchanged.
int mask= (y << p) & (~(~0 << (p+n))); // a mask which has required bits from y in positions to be set , rest all bits 0.
printf("\nCheckpoint : mask= %x x_t= %x\n",mask,x_t);
int result= mask|x_t;
return result;
}
But I somehow feel the logic is long and can be optimized, but can't think of any other way yet.
Can anyone suggest any optimization to this please?

To make an n bit mask:
mask_y = (1U << n) - 1;
To start it at bit p:
mask_x = mask_y << p;
Clear the appropriate bits in x:
x &= ~mask_x;
Extract the bits from y:
y &= mask_y;
Upshift them to position p:
y <<= p;
Put it all together:
result = x | y;
Or in a more compact form:
mask = (1U << n) - 1;
result = x & ~(mask << p);
result |= (y & mask) << p;

Related

Do an arithmetic left shift of x by n bits (C)

Me and my group of 4 people are both completely blanking on how to correctly do an arithmetic left shift of an int x, by an amount of n bits.
It is a for a homework problem on bit manipulation for C. We are not allowed to use loops, if statements, or any operations over 15. I've attached the code given below. Also, the simple solution x << n does not work, even though I'm sure we are missing something obvious. If anyone could help or provide guidance, it would be much appreciated.
/*
* arithLeftShift - Do an arithmetic left shift of x by n bits.
* Can assume that 0 <= n <= 31
* Examples: arithLeftShift(0x87654321,4) = 0xF6543218
* Legal ops: ~ & ^ | + << >> !
* Max ops: 15
* Rating: 3
*/
int arithLeftShift(int x, int n) {
return 0;
}
Current error message:
Test arithLeftShift(-2147483648[0x80000000],1[0x1]) failed...
...Gives 0[0x0]. Should be -2147483648[0x80000000
Actually, It is not arithmetic left shift.It's your arithLeftShift with your sign bit needn't a left shift. And the high bits needed to be shifted to the low position, It looks like a cycle shift.
#include<stdio.h>
int main()
{
arithLeftShift(0x87654321,4);
}
int arithLeftShift(int x,int n)
{
int temp,i; //define two auto variables,
i=x>>(32-n);//i for x's high n bits.
temp=x<<n;//temp for x left shift n bits
if(x>0)//sign bit is 0,
{
x=temp+i;
x=x>0?x:x^0x80000000;//change the x sign bit is 0;
}
else
{//when you do right shift, there will be different with different compliers and your x.
if(i>0){//This means when you do right shift, 0 be inserted into high bits.
x=temp+i;
}
else
{
i=(0x80000000>>(32-n));
x=temp+i;
}
x=x>0?~(x^(~0x80000000)):x;//change the x sign bit is 1
printf("%x\n",x);
}
}
Your ask seems to be to "Rotate" the integer "Left", "n" number of times but retain the "Sign Bit"(MSB) if set.
One solution would be......
#include <stdio.h>
#define INT_BITS 32
int arithLeftShift(int x, int n) {
int res;
res = (x << n | (x >> (INT_BITS - n) & ~(~0 << n))) | x & (~0 << (INT_BITS - 1));
return res;
}
int main(){
int x = 0x87654321;
int n = 4;
printf("0x%x\n",arithLeftShift(x,n));
}
Explanation:
(x << n)
Left shift x, n times - the last n bits are zero.
(x >> (INT_BITS - n) & ~(~0 << n))
Right shift x (INT_BITS - n) times to put the first n bits at the correct position and "AND" it with ~(~0 << n) to set the upper bits to zero.This will take care of "sign extension", if any.
(x << n | (x >> (INT_BITS - n) & ~(~0 << n)))
"OR" them to perform the "Rotate Left" operation.
x & (~0 << (INT_BITS - 1)
Left shift "-1", 31 times and "AND" it with x to check if the MSB of x is set.
(x << n | (x >> (INT_BITS - n) & ~(~0 << n))) | x & (~0 << (INT_BITS - 1))
Finally "OR" the above expressions to get your answer.

split 32 bit instruction into bytes and move result to another address using c

i have a 32 bit instruction that i wish to split into four bytes.
Let say the instruction looks like this:
yyyyyzzzzzzxxxxxx?????????
The instruction is a word that consists of four unsigned ints. y represents the operation code, and ??? are for the unused space. I am working on a big-endian machine.
What I would like to happen is to move the values from z + w to a.
I have never worked in C before but I have tried to do it like this.
Here is how I read the word, just so I ca print out each byte:
unsigned int a, b, c, o;
w = instruction << 24;
z = instruction << 16;
x = instruction << 8;
y = instruction;
Here I print unsigned values, just to check what the result are.
printf("%u\n", w);
printf("%u\n", z);
printf("%u\n", x);
printf("%u\n", y);
printf("\n");
regs[x] = instruction + instruction << 8;
if I print out the values of regs[x] after this, then I can see that I has a value now, but is this the correct way of doing it? When I do like this, do I set the register = z + w?
EDIT
Mabye i should get the bits like this?
y = (inst >> 24) & 077;
x = (inst >> 16) & 0xffff;
z = (inst >> 8) & 0xffff;
w = (inst) & 0xffff;
and then do like this:
regs[y] = z + w;
If you like to use only bit positions and counts you can build a bit mask of i.e. 9 bits with setting the next bit and decrement (1<<10)-1. So your values are
#define MASK(n) ((1<<(n+1))-1)
unsigned int w = instruction & MASK(9);
unsigned int x = (instruction >> 9) & MASK(6);
unsigned int z = (instruction >> 15) & MASK(6);
unsigned int y = (instruction >> 21) & MASK(5);
all values are down shifted. So if you like to combine z and w you will have to
unsigned int zw = z<<9 | w;
because w contains 9 bits, or
unsigned int wz = w<<6 | z;
because z contains 6 bits.

Setting Bits in C

I'm trying to do the following:
Write a func setbits(x,p.n,y) that returns x with n bits that begin at
position p set to the rightmost n bits of y,leaving the other bits
unchanged?
I tried it like this but not getting correct answers. Can anyone tell where I am wrong?
unsigned setbits(unsigned x,int p,int n,unsigned y)
{
return (x>>p & (y|(~0<<n)));
}
Something like:
unsigned setbits(unsigned x,int p,int n,unsigned y)
{
unsigned mask = (1U << n) - 1U; // n-bits
y &= mask; // rightmost n bits of y
y <<= p; // which begin at position p
mask <<= p; //idem
x &= ~mask; //set the 0s
x |= y; //set the 1s
return x;
}
Or if you want to do it in fewer lines, more difficult to debug, but waaaay cooler:
unsigned setbits(unsigned x,int p,int n,unsigned y)
{
unsigned mask = (1U << n) - 1U; // n-bits
return (x & ~(mask << p)) | ((y & mask) << p);
}
Kernighan and Ritchie, 2nd edition, exercise 2-6. The solution is from http://users.powernet.co.uk/eton/kandr2/krx206.html :
(x & ((~0 << (p + 1)) | (~(~0 << (p + 1 - n))))) | ((y & ~(~0 << n)) << (p + 1 - n))
You x>>() so you loose x rightmost bits and then never restore them later in you function.
One can not set bits using only & because the result depends on both operands unless you know one of them consists only of 1
(y|(~0<<n)) is supposed to cut bits from y but it's not, this time | is not the right tool, use & and appropriate second operand.
Here is the solution(I bet there is shorter one, but this is straight-forward):
(x & ~(~(~0<<n)<<p) | (y&~(~0<<n)) << p);
Left part of | clears the place in x(n bits at position p) and the right part brings y bits.
Catching the last n bits of y: (will be a number with the last n bits equal to y, and the others set to zero)
last_n_bits_of_y = y & (((1<<(n+1))-1);
then we can offset it by (32-n-p+1) (check this!)
last_n_bits_of_y_offset = last_n_bits_of_y << (32-n-p+1);
now we erase the bits of x we want to change:
new_x = x & (~( (((1<<(n+1))-1) << (32-n-p+1) ) );
and populate it with our bits:
new_x = new_x & last_n_bits_of_y_offset;
That's it! Didn't really test it, but hopefully, you'll get the idea.

replace byte in 32 bit number

I have a function called replaceByte(x,n,c) that is to replace byte n in x with c with the following restrictions:
Bytes numbered from 0 (LSB) to 3 (MSB)
Examples: replaceByte(0x12345678,1,0xab) = 0x1234ab78
You can assume 0 <= n <= 3 and 0 <= c <= 255
Legal ops: ! ~ & ^ | + << >>
Max ops: 10
int replaceByte(int x, int n, int c) {
int shift = (c << (8 * n));
int mask = 0xff << shift;
return (mask & x) | shift;
}
but when I test it I get this error:
ERROR: Test replaceByte(-2147483648[0x80000000],0[0x0],0[0x0]) failed...
...Gives 0[0x0]. Should be -2147483648[0x80000000]
after realizing that * is not a legal operator I have finally figured it out...and if you are curious, this is what I did:
int replaceByte(int x, int n, int c) {
int mask = 0xff << (n << 3);
int shift = (c << (n << 3));
return (~mask & x) | shift;
}
Since this looks like homework I'm not going to post code, but list the steps you need to perform:
Cast c into a 32-bit number so you don't lose any bits while shifting
Next, shift c by the appropriate number of bits to the left (if n==0 no shifting, if n==1 shift by 8 etc.)
Create a 32-bit bitmask that will zero the lowest 8 bits of x, then shift this mask by the same amount as the last step
Perform bitwise AND of the shifted bitmask and x to zero out the appropriate bits of x
Perform bitwise OR (or addition) of the shifted c value and x to replace the masked bits of the latter
Ahh... You are almost there.
Just change
return (mask & x) | shift;
to
return (~mask & x) | shift;
The mask should contain all ones except for the region to be masked and not vice versa.
I am using this simple code and it works fine in gcc
#include<stdio.h>
int replaceByte(int x, int n, int c)
{
int shift = (c << (8 * n));
int mask = 0xff << shift;
return (~mask & x) | shift;
}
int main ()
{
printf("%X",replaceByte(0x80000000,0,0));
return 0;
}
Proper solution is for c = 0 as well:
int replaceByte(int x, int n, int c)
{
int shift = 8 * n;
int value = c << shift;
int mask = 0xff << shift;
return (~mask & x) | value;
}

retrieve byte from 32 bit integer using bitwise operators

Here is the problem and what I currently have, I just don't understand how it is wrong...
getByte - Extract byte n from word x Bytes numbered from 0 (LSB) to
3 (MSB) Examples: getByte(0x12345678,1) = 0x56 Legal ops: ! ~ &
^ | + << >> Max ops: 6 Rating: 2
int getByte(int x, int n) {
return ((x << (24 - 8 * n)) >> (8 * n));
}
Your shifting doesn't make any sense - first, you shift left by (24 - 8n) bits, then you shift back right by 8n bits. Why? Also, it's wrong. If n is 0, you shift x left by 24 bits and return that value. Try pen and paper to see that this is entirely wrong.
The correct approach would be to do:
int getByte(int x, int n) {
return (x >> 8*n) & 0xFF;
}
Unless i am totally mistaken, your code is mathematically incorrect.
getByte(0x000000ff, 0) {
24 - 8 * n = 24;
8 * n = 0;
0x000000ff << 24 = 0xff000000;
0xff000000 >> 0 = 0xff000000;
return 0xff000000; // should return 0xff
}
Not being allowed to use operators - and especially * is a problem (can't do * 8). I came up with this:
uint8_t getByte (uint32_t x, int n) {
switch (n) {
case 0:
return x & 0xff;
case 1:
return (x >> 8) & 0xff;
case 2:
return (x >> 16) & 0xff;
case 3:
return x >> 24;
}
}
Not exactly beautiful, but it conforms to the problem description: 6 operators, all of them legal.
EDIT: Just had a (pretty obvious) idea for how to avoid * 8
uint8_t getByte (uint32_t x, int n) {
return (x >> (n << 3)) & 0xff;
}
I don't understand how your function works. Try this instead:
int getByte(int x, int n)
{
return (x >> (8 * n)) & 0xFF;
}

Resources