#include <stdio.h>
#include <limits.h>
/*
* CS:APP Data Lab
*
* <Please put your name and userid here>
*
* bits.c - Source file with your solutions to the Lab.
* This is the file you will hand in to your instructor.
*
* WARNING: Do not include the <stdio.h> header; it confuses the dlc
* compiler. You can still use printf for debugging without including
* <stdio.h>, although you might get a compiler warning. In general,
* it's not good practice to ignore compiler warnings, but in this
* case it's OK.
*/
#if 0
/*
* Instructions to Students:
*
* STEP 1: Read the following instructions carefully.
*/
You will provide your solution to the Data Lab by
editing the collection of functions in this source file.
INTEGER CODING RULES:
Replace the "return" statement in each function with one
or more lines of C code that implements the function. Your code
must conform to the following style:
int Funct(arg1, arg2, ...) {
/* brief description of how your implementation works */
int var1 = Expr1;
...
int varM = ExprM;
varJ = ExprJ;
...
varN = ExprN;
return ExprR;
}
Each "Expr" is an expression using ONLY the following:
1. Integer constants 0 through 255 (0xFF), inclusive. You are
not allowed to use big constants such as 0xffffffff.
2. Function arguments and local variables (no global variables).
3. Unary integer operations ! ~
4. Binary integer operations & ^ | + << >>
Some of the problems restrict the set of allowed operators even further.
Each "Expr" may consist of multiple operators. You are not restricted to
one operator per line.
You are expressly forbidden to:
1. Use any control constructs such as if, do, while, for, switch, etc.
2. Define or use any macros.
3. Define any additional functions in this file.
4. Call any functions.
5. Use any other operations, such as &&, ||, -, or ?:
6. Use any form of casting.
7. Use any data type other than int. This implies that you
cannot use arrays, structs, or unions.
You may assume that your machine:
1. Uses 2s complement, 32-bit representations of integers.
2. Performs right shifts arithmetically.
3. Has unpredictable behavior when shifting an integer by more
than the word size.
EXAMPLES OF ACCEPTABLE CODING STYLE:
/*
* pow2plus1 - returns 2^x + 1, where 0 <= x <= 31
*/
int pow2plus1(int x) {
/* exploit ability of shifts to compute powers of 2 */
return (1 << x) + 1;
}
/*
* pow2plus4 - returns 2^x + 4, where 0 <= x <= 31
*/
int pow2plus4(int x) {
/* exploit ability of shifts to compute powers of 2 */
int result = (1 << x);
result += 4;
return result;
}
FLOATING POINT CODING RULES
For the problems that require you to implent floating-point operations,
the coding rules are less strict. You are allowed to use looping and
conditional control. You are allowed to use both ints and unsigneds.
You can use arbitrary integer and unsigned constants.
You are expressly forbidden to:
1. Define or use any macros.
2. Define any additional functions in this file.
3. Call any functions.
4. Use any form of casting.
5. Use any data type other than int or unsigned. This means that you
cannot use arrays, structs, or unions.
6. Use any floating point data types, operations, or constants.
NOTES:
1. Use the dlc (data lab checker) compiler (described in the handout) to
check the legality of your solutions.
2. Each function has a maximum number of operators (! ~ & ^ | + << >>)
that you are allowed to use for your implementation of the function.
The max operator count is checked by dlc. Note that '=' is not
counted; you may use as many of these as you want without penalty.
3. Use the btest test harness to check your functions for correctness.
4. Use the BDD checker to formally verify your functions
5. The maximum number of ops for each function is given in the
header comment for each function. If there are any inconsistencies
between the maximum ops in the writeup and in this file, consider
this file the authoritative source.
/*
* STEP 2: Modify the following functions according the coding rules.
*
* IMPORTANT. TO AVOID GRADING SURPRISES:
* 1. Use the dlc compiler to check that your solutions conform
* to the coding rules.
* 2. Use the BDD checker to formally verify that your solutions produce
* the correct answers.
*/
#endif
/*
* bang - Compute !x without using !
* Examples: bang(3) = 0, bang(0) = 1
* Legal ops: ~ & ^ | + << >>
* Max ops: 12
* Rating: 4
*/
int bang(int x) {
return ((x | (~x+1)) >> 31) + 1;
}
/*
* bitCount - returns count of number of 1's in word
* Examples: bitCount(5) = 2, bitCount(7) = 3
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 40
* Rating: 4
*/
int bitCount(int x) {
#define const1 0x55
#define const2 0x33
#define const3 0x0F
#define const4 0xFF
int y = x;
int iconst1 = const1; // this needs to be 0x55555555
int iconst2 = const2; // this needs to be 0x33333333
int iconst3 = const3; // this needs to be 0x0F0F0F0F
int iconst4 = 0; // this needs to be 0x00FF00FF
int iconst5 = 0; // this needs to be 0x0000FFFF
int negx;
iconst1 = (iconst1 <<8) | const1;
iconst1 = (iconst1 << 16) | iconst1; // now iconst1 is 0x55555555
iconst2 = (iconst2 <<8) | const2;
iconst2 = (iconst2 << 16) | iconst2; // now iconst2 is 0x33333333
iconst3 = (iconst3 << 8) | const3;
iconst3 = (iconst3 << 16) | iconst3; // now iconst3 is 0x0F0F0F0F
iconst4 = ((((iconst4 << 8) | const4) << 16 | const4)); // now iconst4 is 0x00FF00FF
iconst5 = ((iconst5 <<16) | const4)<<8 | const4; // now iconst5 0x0000FFFF
// Basically, if we take a 2 bit number the number can be 11, 10, 01 and 00
// to count the number of 1s in this 2 bit number-
// right shift by 1- 01; 01; 00; 00
// subtract from the original number- (11 - 01) = 2; (10 - 01) = 1; (01- 00) = 1; 00-00 = 0
// you will get the number of 1s.
// so we will start with:
// y = y - (( y >> 1) & 0x55555555
// Now, each 2 bit will have the correct count of number of bits in those 2 bits.
// as soon as we right shift by 1, the higher order bit of the 2 bits should be masked out
// since it is always zero in a 2 bit arithmetic. so, we mask it out with the pattern 0101 01 01
// which becomes 0x55555555
negx = ~((y>>1) & iconst1) + 1; // taking 2's complement of (y >>1) & iconst1
y = y + negx;
// now every adjascent 2 bits have the number of bits in the original numbers' 2 bits.
// we have to start adding the adjascent 2 bits.
// y = (y & 0x33333333) + ((y >>2) & 0x33333333)
// here we right shift the value by 2, and add to the original value
// however the higher order 2 bits of the 4 bits we just accumulated have to be masked out.
// so we and it with the pattern 0011 0011 0011 etc- which is 0x33333333
y = ((y >>2) & iconst2) + (y & iconst2);
// at this time every 4 bits will have one of the following values:
// 0000 or 0001 or 0011 or 0100 - the number of 1s in each 4 bits of the original number.
// if we do y + (y >>4)- then each lower 4 bits will have the right numbers.
// but upper 4 bits of the result is irrelevant. so, we can mask out upper 4 bits with
// anding with 0F.
// so this is what we do:
// y = ( y + (y >> 4)) & 0x0F0F0F0F
y = ((y>>4) + y) & iconst3;
// now all 4 bytes will have the proper count of the 1s in the original bytes.
// The bytes will have the following possible values:
// 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
// we can add the adjascent bytes by adding the number right shifted by 8 to the number.
// however, need to mask out the odd numbered bytes .
// so we do
// y = ( y + ( y >> 8)) & 0x00ff00ff
y = ((y >>8) +y) & iconst4;
// now the two halfs of the word (first two bytes and last two bytes) have the count
// we need to add them. it is done by: adding the number right shifted by 16 to the number.
// of course we need to mask out the first 2 bytes of the word.
// so it is done by:
// y = ( y + (y >>16)) & 0x0000FFFF;
y = ((y >>16) +y) & iconst5;
return y;
}
/*
* bitOr - x|y using only ~ and &
* Example: bitOr(6, 5) = 7
* Legal ops: ~ &
* Max ops: 8
* Rating: 1
*/
int bitOr(int x, int y) {
int num1 = ~x;
int num2 = ~y;
return (~(num1 & num2));
}
/*
* bitRepeat - repeat x's low-order n bits until word is full.
* Can assume that 1 <= n <= 32.
* Examples: bitRepeat(1, 1) = -1
* bitRepeat(7, 4) = 0x77777777
* bitRepeat(0x13f, 8) = 0x3f3f3f3f
* bitRepeat(0xfffe02, 9) = 0x10080402
* bitRepeat(-559038737, 31) = -559038737
* bitRepeat(-559038737, 32) = -559038737
* Legal ops: int and unsigned ! ~ & ^ | + - * / % << >>
* (This is more general than the usual integer coding rules.)
* Max ops: 40
* Rating: 4
*/
int bitRepeat1(int x, int n) {
int castval;
/** mask off all the bits to the left of nth bit into repeat **/
int neg_one = -1;
int repeat = ~(neg_one << n) & x;
//nMax = all 1s if n== 32 . else nMax is all 0s
int nMax = -!(n^32);
/* first shift- 1 X */
repeat = (repeat << n) | repeat;
/** second shift - 2X- overflow bits come into play */
n = n* 2;
/* set castval to -1 iff n<32 and 0 otherwise */
castval = ~((31-n)>>31);
repeat = repeat | ((repeat << n) & castval);
/* third shift- 4 X - overflow check still applies */
n = n* 2;
castval = ~((31-n)>>31);
repeat = repeat | ((repeat << n) & castval);
/* fourth shift 8 X overflow check will continue */
n = n* 2;
castval = ~((31-n)>>31);
repeat = repeat | ((repeat << n) & castval);
/* fifth and LASt shift 16 X overflow check will continue */
n = n* 2;
castval = ~((31-n)>>31);
repeat = repeat | ((repeat << n) & castval);
return (repeat & ~nMax) | (x & nMax);
}
int bitRepeat( int x, int n){
int x1 = !(n/32);
int x2 = ! (n/16);
int x3 = ! (n/8);
int x4 = ! (n/4);
int x5 = ! (n/2);
unsigned int a = (x <<(32-n));
unsigned int rpt = a >> (32-n);
rpt = rpt << (n* x1) | (rpt *x1);
rpt = rpt << ((n*2) *x2) | (rpt *x2);
rpt = rpt << ((n*4) * x3) | (rpt *x3);
rpt = rpt << ((n*8) * x4) | (rpt *x4);
rpt = rpt << ((n*16) * x5) | (rpt *x5);
return rpt;
}
/*
* fitsBits - return 1 if x can be represented as an
* n-bit, two's complement integer.
* 1 <= n <= 32
* Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 2
*/
int fitsBits(int x, int n) {
/* if nth bit of the X (counting from right) is 1, it won't fit */
int rval, hob_remain;
/* computing remaining high order bits beyond the "n" shift bits */
hob_remain = 32 + (~n + 1); // taking 2s complement of n to make it -n and adding it to 32
/* propagating the MSB of X to the all the bits to the left of X */
rval = (x<<hob_remain) >> hob_remain; // left shifting by remaining HOB bits gets the MSB of x to MSB of int; then arithmetic shift.
return !(rval ^ x); // this actually returns rval == x;
}
/*
* 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 >> (n <<3)) & 0xFF;
}
/*
* isLessOrEqual - if x <= y then return 1, else return 0
* Example: isLessOrEqual(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isLessOrEqual(int x, int y) {
int diff_sgn = !(x>>31)^!(y>>31); //is 1 when signs are different
int a = diff_sgn & (x>>31); //diff signs and x is neg, gives 1
int b = !diff_sgn & !((y+(~x+1))>>31); //same signs and difference is pos or = 0, gives 1
int f = a | b;
return f;
}
/*
* isPositive - return 1 if x > 0, return 0 otherwise
* Example: isPositive(-1) = 0.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 3
*/
int isPositive(int x) {
return (!(x >>31)) & ~(!(x^0));
}
/*
* logicalShift - shift x to the right by n, using a logical shift
* Can assume that 0 <= n <= 31
* Examples: logicalShift(0x87654321,4) = 0x08765432
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 3
*/
int logicalShift(int x, int n) {
/* Doing an arithmetic shift and zeroing out all the bits to the left of previous MSB */
return (x >> n) & ~(((0x1 << 31) >> n) << 1);
}
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return 0x01 <<31;
}
int main(void) {
// your code goes here
printf("Bang of 9 is %d\n", bang
(9)); printf("Bang of INT_MIN is %d\n", bang
(INT_MIN
)); printf("Bang of INT_MAX is %d\n", bang
(INT_MAX
)); printf("Bang of 0 is %d\n", bang
(0)); printf("Bitcount of 9 is %d\n", bitCount
(9)); printf("Bitcount of INT_MIN is %d\n", bitCount
(INT_MIN
)); printf("Bitcount of INT_MAX is %d\n", bitCount
(INT_MAX
)); printf("Bitcount of -1 is %d\n", bitCount
(-1));
printf("bitwise or of 6 and 5 is %d\n", bitOr
(6,5)); printf("bitwise or of INT_MIN and INT_MAX is %d\n", bitOr
(INT_MIN
,INT_MAX
));
printf("bitrepeat of 7 & 4 = %8x \n", bitRepeat
(7,4)); printf("bitrepeat of 1 & 1 = %8x \n", bitRepeat
(1,1)); printf("bitrepeat of 0x13f & 8 = %8x \n", bitRepeat
(0x13f,8)); printf("bitrepeat of 0xfffe02 & 9 = %8x \n", bitRepeat
(0x00fffe02,9)); printf("bitrepeat of -559038737 & 31 = %d \n", bitRepeat
(-559038737,31)); printf("bitrepeat of -559038737 & 32 = %d \n", bitRepeat
(-559038737,32)); printf("bitrepeat of INT_MIN & 32 =%8x\n", bitRepeat
(INT_MIN
, 32)); printf("bitrepeat of 0x50c9e87e & 0x3 is %8x\n", bitRepeat
(0x50c9e87e, 0x3)); printf("bitrepeat of digital 0x50c9e87e & 0x3 is %8x\n", bitRepeat
(1355409534, 0x3));
printf("fitsBits of 5 & 3 = %d\n", fitsBits
(5,3)); printf("fitsBits of -4 &3 = %d\n", fitsBits
(-4, 3));
printf("getByte of 0x12345678, 1 %08x\n", getByte
(0x12345678,1)); printf("getByte of 0x87654321, 3 %08x\n", getByte
(0x87654321,3)); printf("isLessorEqual of 4, 5 is = %d\n", isLessOrEqual
(4,5)); printf("isLessorEqual of INT_MIN, INT_MAX is = %d\n", isLessOrEqual
(INT_MIN
,INT_MAX
)); printf("isLessorEqual of INT_MAX, INT_MIN is = %d\n", isLessOrEqual
(INT_MAX
,INT_MIN
)); printf("isLessorEqual of INT_MAX, INT_MIN+1 is = %d\n", isLessOrEqual
(INT_MAX
,INT_MIN
+1)); printf("isLessorEqual of INT_MIN, INT_MIN is = %d\n", isLessOrEqual
(INT_MIN
,INT_MIN
)); printf("isLessorEqual of INT_MAX, INT_MAX is = %d\n", isLessOrEqual
(INT_MAX
,INT_MAX
));
printf("IsPositive (-1) = %d\n", isPositive
(-1)); printf("IsPositive (INT_MIN) = %d\n", isPositive
(INT_MIN
)); printf("IsPositive (0) = %d\n", isPositive
(0)); printf("IsPositive 0x7ffffffe is %d\n", isPositive
(0x7ffffffe));
printf("logical shift (0x87654321,4) = %08x\n", logicalShift
(0x87654321,4));
printf("tmin value = %08x In Decimal %d\n", tmin
(), tmin
());
return 0;
}