Setting Specific Bits to Reflect a Variable Value

Sep 28, 2011 at 9:39pm
Hello,

Up until now, I haven't had any problems with my C++ or VB classes. However, bitwise aspects of C++ are not my strong point, so I was wondering if I could get a little guidance...

Here is what I need to do:

Write a function whose prototype is
unsigned int Compress(unsigned int age, unsigned int grade, char sex, double GPA);

The input parameters consist of a child’s age (from 3 through 18), grade in school (from 0 through 12), sex (either ‘M’ or ‘F’), ange grade point average (a number from 0.0 [all F’s] through 4.0 [all A’s]). You may assume that the GPA has exactly one digit after the decimal point. Your function should store the input parameters into the low-order 16 bits of an unsigned int, which is then returned to the calling program. The input parameters should be compressed according to the following diagram.

Age: bits 12-15
Grade: 8-11
Sex : 7
Whole part of GPA: 4-6
Fractional part of GPA: 0-3

A sex of ‘M’ should be stored as one (1), and a sex of ‘F’ should be stored as zero (0).

***So, what I am needing to know is:

How would I assign the bits 12-15 a value from the 'age' variable? For example, if the age was 10, I would need bits 12-15 to be 1010.

I don't want anyone to write my code for me, but maybe just point me in the right direction of a function I can use...I tried the bitset<> function, but it didn't seem to let me pick a certain range of bits to flip...

Thanks for any help.
Sep 28, 2011 at 9:58pm
Let's assume "wxyz" are 4 bits that represent the age.
You want to insert them into a 16 bit value as bits 12-15 (bit 0 being the least significant bit.)
However, you want to do this without changing the other bits' values.

  abcd efgh ijkl mnop	 (unknown 16 bit value)
& 0000 1111 1111 1111  = 0x0fff
 _____________________

  0000 efgh ijkl mnop
| wxyz 0000 0000 0000  = 0000 0000 0000 wxyz << 12
 _____________________

  wxyz efgh ijkl mnop

Sep 28, 2011 at 10:09pm
This is a pretty good exercise for learning this kind of thing.

There are 3 concepts you need to grasp:

1) The AND operator (&) is used to "extract" bits. That is, you tell it which bits you want, and it will "switch off" all other bits:

1
2
3
4
5
6
int foo = 0x12;

// I only want bits 0-2 of foo
int bits = foo & 0x07;

cout << hex << bits; // prints "2" 


As you can see, this "extracted" the low 3 bits and "switched off" that high bit. This works like so:

1
2
3
4
5
0x12 = %00010010
0x07 = %00000111
              ^
              &
0x02 = %00000010


2) The OR operator (|) does the opposite. It "switches on" whatever bits you tell it.

1
2
3
4
5
6
int foo = 0x1C;

// I want to flip on bits 0, 3, and 5
int bits = foo | 0x29;

cout << hex << bits;  // prints 3d 


This works like so:

1
2
3
4
5
0x1C = %00011100
0x29 = %00101001
          ^^^^ ^
          |||| |
0x3D = %00111101


3) Bitshifting simply "moves" all the bits over by howevery many bit positions.

I'd explain this more but I have to go back to work!!!

EDIT: And I'm too slow anyway!!!!
Last edited on Sep 28, 2011 at 10:09pm
Sep 28, 2011 at 10:48pm
Thanks for the replies. I figured it out just before the replies posted...however, I didn't go the same route as y'all. Here is what I did:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unsigned int Compress(unsigned int age, unsigned int grade, char sex, double GPA)
{
	unsigned int num = 0;
	int gpaWhole = static_cast <int> (GPA);
	double gpaTemp = GPA * 10;
	unsigned int gpaFraction = (unsigned int) gpaTemp % 10;

	if (sex == 'M')
	{
		sex = 1;
	}else{
		sex = 0;
	}
	
	num = ((age - 3) << 12) + (grade << 8) + (sex << 7) + (gpaWhole << 4) + (gpaFraction);

	return num;
}


Basically, this just assigns a number value (instead of M of F) for sex, then puts the values for each variable into num, using the assigned bit locations for each. It probably isn't the most efficient way, but it works for all the data sets that are provided in the assignment.

I tried using the & and && operators, but I couldn't seem to get the values to combine to form a 32-bit number.

Thanks again and I am sure I will be posting more on here again. :)
Sep 29, 2011 at 7:36pm
Well if it works it works, but I'm confoosed and confusuled on lines 4-6. If GPA is coming in the format "W.F", then just multiply by 10 (gpa *= 10) and now it looks like "WF."... Then cast to an int and save yourself the trouble. (I.e. turn a 3.4 into a 34)
Sep 29, 2011 at 9:19pm
I can see how that part would be confusing without the comments I added later. The GPA need to be divided into an int for the left side of the decimal and another int for the right side...i.e. 4.9 would need to have two ints, 4 and 9, and their place in the bits would be different.
Sep 29, 2011 at 10:30pm
I sucked bitwise operators until I learned to read binary well, and read through this: http://www.cprogramming.com/tutorial/bitwise_operators.html

Along with the power of two exercise at the end of that article, heres a few more I did from the C Programming Language that are good ways to keep in practice and get solid with them, though I rarely end up using them:

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.
Exercise 2-7. Write a function invert(x,p,n) that returns x with the n bits that begin at position p
inverted (i.e., 1 changed into 0 and vice versa), leaving the others unchanged.
Exercise 2-8. Write a function rightrot(x,n) that returns the value of the integer x rotated to the
right by n positions.

I can give you the solutions if you want :)

Also you can abbreviate your code with on 8-13 with the ?: operator :)
 
sex = (sex == m) ? 1 : 0;
Last edited on Sep 30, 2011 at 1:07am
Topic archived. No new replies allowed.