[关闭]
@Wayne-Z 2017-11-05T07:27:12.000000Z 字数 3728 阅读 4454

Data Lab: Manipulating Bits

ssd6



Environment

Analisis

This project need we use just 8 operators to finish 10 puzzles. So lets review these 8 operators and their uses as follows.

  • '!' logical operation NOT
  • '~' bit level operation NOT
  • '&' bit level operation AND
  • '^' bit level operation EXCLUSIVE-OR
  • ' | ' bit level operation OR
  • '+' arithmatical plus
  • '<<' left shift
  • '>>' arithmatical right shift for signed number in the implemantation, logical right shift for unsigned number

Then we can take a look at this puzzles, we can know the basic idea for many problems is to find the combination of those operators that has equivalent truth values of the expected outcomes.

Puzzles

bitAnd(x,y)

  1. /*
  2. * bitAnd - x&y using only ~ and |
  3. * Example: bitAnd(6, 5) = 4
  4. * Legal ops: ~ |
  5. * Max ops: 8
  6. * Rating: 1
  7. */
  8. int bitAnd(int x, int y) {
  9. return ~(~x|~y);
  10. }

For this function, we just need to look at the true value table and find a equivalent way.

x y x&y ~x ~y ~(~x |~y)
0 0 0 1 1 0
0 1 0 1 0 0
1 0 0 0 1 0
1 1 1 0 0 1

bitOr(x,y)

  1. /*
  2. * bitOr - x|y using only ~ and &
  3. * Example: bitOr(6, 5) = 7
  4. * Legal ops: ~ &
  5. * Max ops: 8
  6. * Rating: 1
  7. */
  8. int bitOr(int x, int y) {
  9. return ~(~x&~y);
  10. }

similarly, we just need to look at the truth value table.

x y x | y ~x ~y ~(~x&~y)
0 0 0 1 1 0
0 1 1 1 0 1
1 0 1 0 1 1
1 1 1 0 0 1

isZero()

  1. /*
  2. * isZero - returns 1 if x == 0, and 0 otherwise
  3. * Examples: isZero(5) = 0, isZero(0) = 1
  4. * Legal ops: ! ~ & ^ | + << >>
  5. * Max ops: 2
  6. * Rating: 1
  7. */
  8. int isZero(int x) {
  9. return !x;
  10. }

This function just need we to use logical not, if x is zero, then x means false, !x is true.

minusOne

  1. /*
  2. * minusOne - return a value of -1
  3. * Legal ops: ! ~ & ^ | + << >>
  4. * Max ops: 2
  5. * Rating: 1
  6. */
  7. int minusOne(void) {
  8. return ~0;
  9. }

This time we need the bit operation not. We can know that signed integer 0 in binary expression is all 0 in each bit, so use ~ we get all 1 which is -1 in decimal.

TMax

  1. /*
  2. * TMax - return maximum two's complement integer
  3. * Legal ops: ! ~ & ^ | + << >>
  4. * Max ops: 4
  5. * Rating: 1
  6. */
  7. int tmax(void) {
  8. return ~(1<<31);
  9. }

to find the max integer in two's complement, we know it is 0x7fffffff, we just need 0x1 left shift 31 bit to get 0x80000000, and use bit level not to make it all 1 except the first bit.

bitXor

  1. /*
  2. * bitXor - x^y using only ~ and &
  3. * Example: bitXor(4, 5) = 1
  4. * Legal ops: ~ &
  5. * Max ops: 14
  6. * Rating: 2
  7. */
  8. int bitXor(int x, int y) {
  9. return ~(~(~x&y)&~(x&~y));
  10. }

It is more compicated than the former, but we still need to use the truth value table.

x y x ^ y ~x ~y (~x&y) (x&~y) (~x&y)|(x&~y)
0 0 0 1 1 0 0 0
0 1 1 1 0 1 0 1
1 0 1 0 1 0 1 1
1 1 0 0 0 0 0 0

However, '|' is not allowed, so we need to use bitOr again thuse we get ~(~(~x&y)&~(x&~y)).

getByte

  1. /*
  2. * getByte - Extract byte n from word x
  3. * Bytes numbered from 0 (LSB) to 3 (MSB)
  4. * Examples: getByte(0x12345678,1) = 0x56
  5. * Legal ops: ! ~ & ^ | + << >>
  6. * Max ops: 6
  7. * Rating: 2
  8. */
  9. int getByte(int x, int n) {
  10. return (x>>(n<<3)&(0xff);
  11. }

This time, we need to use a mask to get the exact byte we need. First we move bits to the start of the byte, we need move 8*n bit, which is equal to n<<3, then we just need a mask has 8 bits' 1, which is 0xff, and use & to mask them. We can also use mask first, but since right shift is arithmatic shift as we mentioned before, it may get some bugs since we need both shift the mask and the number if x is negative.

isEqual

  1. /*
  2. * isEqual - return 1 if x == y, and 0 otherwise
  3. * Examples: isEqual(5,5) = 1, isEqual(4,5) = 0
  4. * Legal ops: ! ~ & ^ | + << >>
  5. * Max ops: 5
  6. * Rating: 2
  7. */
  8. int isEqual(int x, int y) {
  9. return !(x^y);
  10. }

What we need to do is using bit level exclusive not to compare their bits to check whether they are equal, and use logical not to check if there are bits that is 1. We can use the truth value table.

x y x ^ y !(x^y)
0 0 0 1
0 1 1 0
1 0 1 0
1 1 0 1

negate

  1. /*
  2. * negate - return -x
  3. * Example: negate(1) = -1.
  4. * Legal ops: ! ~ & ^ | + << >>
  5. * Max ops: 5
  6. * Rating: 2
  7. */
  8. int negate(int x) {
  9. return ~x+1;
  10. }

We can know that the definetion of twos complement. So we just need to take the back and plus 1.

isPositive

  1. /*
  2. * isPositive - return 1 if x > 0, return 0 otherwise
  3. * Example: isPositive(-1) = 0.
  4. * Legal ops: ! ~ & ^ | + << >>
  5. * Max ops: 8
  6. * Rating: 3
  7. */
  8. int isPositive(int x) {
  9. return !(x>>31)&(!(!(x&(0x7FFFFFFF))));
  10. }

This take some time for some cases. First we need to right shift 31 bits to check its sign bit. If it is positive, x>>31 get all 0, but if x is not, x<31 get all 1. And since x should bigger than 0, so we still need (x&(0x7FFFFFFF)) to ensure x is not 0;

Outcom

After compilation, we can run the program for test, we can see it passes all tests.
After this exercise, I got a deeper understanding of bit operation and the machine expression of number.

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注