"CSAPP" known programmer Bible, although Chinese translation for "in-depth understanding of computer systems", but in fact is not so "deep", but coverage is very broad, commonly used as a freshman computer science textbook introduction course. Supporting long heard of the book is a classic experiment, this time to review the new (third edition), intends to do about all of the experiments, also wrote a series of blog posts good record during the experiment. Experiments can book companion Web site CSAPP: Lab Assignments downloaded from this first experiment - Start bit operation.
Outline
This experiment was chapter "indicates processing information" supporting experiments, requires the use of a subset of C language implementation specific height restriction logic, integers, floating point functions. Continue to use the argument of the first chapter, information is context-bit addition, computer system all information is represented by a series of bits (or a string of binary digits), the second chapter stresses the C language integer and floating-point numbers encoding, i.e. typically using a computer how a series of bits used to represent the integer and floating point:
- Unsigned integer: straight binary coding
- Signed integer: twos complement, MSB negative right
- Float: the IEEE 754
Also removed from the memory 4 bytes \ (0x80000000 \) , to see it as an unsigned integer, that is, \ (2147483648 \) ; to see it as a signed integer, is \ (- 2147483648 \) ; it as a single precision floating point of view, is \ (- 0 \) . The so-called context, is the interpretation of this bit string of ways, cross as a peak. It is noteworthy that, although in almost all systems, C language integer and floating-point numbers are encoded so, but the C language standard itself does not have such a requirement, do not know their lifetime can encounter non-mainstream encoding.
If you do not fully grasp bit operating encoding and C language of these numbers, it is certainly not a complete experiment of. Experiment one is nice because you will repeatedly recall the basics, deep into the details of the experiments done to forget forget :)
premise
Despite the standard C language, but in the case Undefined Behavior or too much, especially for deep underlying bit operation, so the preset test: 32-bit signed integer using twos complement coding; displacement arithmetic right shift operation, high up the sign bit. Experiments also requires: macro can not be used; the use of a constant operation is not greater than an integer of 0xFF. Here's a by-function recording experiment.
bITAND
Use ~
and |
implement &
, there is a very simple formula, but remember, the auxiliary thinking map with Wayne: The Complete Works indicates that all bits are 1, x
and y
represent a specific location for a child 1 set, imagine ~
, |
and &
Wayne map, click on the launch of the sub-formulas.
/*
* bitAnd - x&y using only ~ and |
* Example: bitAnd(6, 5) = 4
* Legal ops: ~ |
* Max ops: 8
* Rating: 1
*/
int bitAnd(int x, int y) {
return ~(~x | ~y);
}
getByte
x
Right n * 8
position, the last byte can be taken by the n * 8 == n << 3
.
/*
* 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;
}
logicalShift
Experimental preset arithmetic shift to the right, then to x
the right n
position and then the mask will fill the high n
position to 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) {
int mask = ~(((1 << 31) >> n) << 1);
return (x >> n) & mask;
}
bitCount
This title like a long time, the idea is to normal x
bit by bit to the right, take the lowest position with 1 mask, and then sum, however, exceeded the number of operators: D Then think of using x & 1
to check x
last bit is 1 if Comparative loss, can be used x & 0x00010001
, so that one can check two, front and rear final 16-bit result can be summarized, however, the number is exceeded operator: D the final x
points of the 8 groups x & 0x11111111
, each inspection 8, with 38 operator, finally reached. This is the largest number of all the problems with operators of a problem.
/*
* 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) {
int mask = 0x11 + (0x11 << 8) + (0x11 << 16) + (0x11 << 24);
int count = (x & mask) + ((x >> 1) & mask) +
((x >> 2) & mask) + ((x >> 3) & mask);
return (count & 7) + ((count >> 4) & 7) + ((count >> 8) & 7) +
((count >> 12) & 7) + ((count >> 16) & 7) + ((count >> 20) & 7) +
((count >> 24) & 7) + ((count >> 28) & 7);
}
bang
Want to start making a fuss 0 above, after all, only bang(0) = 1
, but that being the case. |
Operation, dichotomy, gradually collected into a high-order low, such as x = x | (x >> 16)
, if the high-order 16-bit words. 1, the lower will be collected on a 16-bit, so-half, the last one collected, just 12 operating symbol.
/*
* bang - Compute !x without using !
* Examples: bang(3) = 0, bang(0) = 1
* Legal ops: ~ & ^ | + << >>
* Max ops: 12`
* Rating: 4
*/
int bang(int x) {
x = x | (x >> 16);
x = x | (x >> 8);
x = x | (x >> 4);
x = x | (x >> 2);
x = x | (x >> 1);
return ~x & 1;
}
tmin
The simplest one question, to be familiar with two's complement.
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return 1 << 31;
}
fitsBits
If x
non-negative, taking into account the n
maximum non-bit two's complement negative number can be expressed as $ 0b0111 ... 111 $ (total n-1
number 1), by masking the x
lower bits n-1
position 0, the upper check 32 - (n - 1)
bits is 0 can be. If x
negative, it first to non-negative ~x
, encoding ~x
the required encoding bits x
are the same.
/*
* 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) {
int minusOne = ~0;
int mask = minusOne << (n + minusOne);
return !((x ^ (x >> 31)) & mask);
}
divpwr2
x >> n
That is, \ (\ lfloor X / 2 ^ n-\ rfloor \) , the result is rounded down, but the problem requires rounding to 0, if the x
non-negative rounding down to 0 i.e. no problem rounding, if x
as negative, need to x
a plus offset value \ (n-2 ^ -. 1 \) , such that the x >> n
rounding up.
/*
* divpwr2 - Compute x/(2^n), for 0 <= n <= 30
* Round toward zero
* Examples: divpwr2(15,1) = 7, divpwr2(-33,4) = -2
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 2
*/
int divpwr2(int x, int n) {
int signBit = (x >> 31) & 1;
int bias = (signBit << n) + (~signBit + 1);
return (x + bias) >> n;
}
negate
n-bit twos complement range is \ ([- ^ {n-2}. 1, \ ^ {n-2}. 1 -. 1] \) , is not symmetric about 0, so that when x
when the minimum value -x
is its own .
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ~x + 1;
}
isPositive
Positive sign bit is the sign bit is 0 0,0, is a special case.
/*
* 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) & (!(x >> 31));
}
isLessOrEqual
isLessOrEqual
Equivalent to !isGreater
realize isGreater
a simple point: If the x
y
different number, it x
must be non-negative y
must be negative; if x
y
the same number, x - y
will not overflow, there must be x - y > 0
, i.e. x - y - 1 >= 0
, i.e. x + ~y >= 0
, checks x + ~y
the sign bit.
/*
* 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 xSign = x >> 31;
int ySign = y >> 31;
int hasSameSign = !(xSign ^ ySign);
int diffSign = (x + ~y) >> 31;
int isXPosYNeg = (!xSign) & ySign;
int isGreater = isXPosYNeg | (hasSameSign & !diffSign);
return !isGreater;
}
ilog2
This question allows the operator 90 is the number of all the questions the operator the most relaxed. ilog2
The essence is to strive x
index of the highest bit 1, if x
a high of 16, 1, and leave the low-order 16-bit; if x
a high of 8 and 1, then do not control the low of 24, and so on. Implement or very clever :)
/*
* ilog2 - return floor(log base 2 of x), where x > 0
* Example: ilog2(16) = 4
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 90
* Rating: 4
*/
int ilog2(int x) {
int high16, high8, high4, high2, high1;
high16 = (!!(x >> 16)) << 4;
x = x >> high16;
high8 = (!!(x >> 8)) << 3;
x = x >> high8;
high4 = (!!(x >> 4) << 2);
x = x >> high4;
high2 = (!!(x >> 2) << 1);
x = x >> high2;
high1 = !!(x >> 1);
return high1 + high2 + high4 + high8 + high16;
}
float_neg
And finally to float, and floating-point problem of operator requirements relaxed a little, you can also use recycled with the judgment statement. The first question, as long as IEEE754 familiar with on the line.
/*
* float_neg - Return bit-level equivalent of expression -f for
* floating point argument f.
* Both the argument and result are passed as unsigned int's, but
* they are to be interpreted as the bit-level representations of
* single-precision floating point values.
* When argument is NaN, return argument.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 10
* Rating: 2
*/
unsigned float_neg(unsigned uf) {
int isNaN = (((uf >> 23) & 0xFF) == 0xFF) && (uf << 9);
return isNaN ? uf : ((1 << 31) ^ uf);
}
float_i2f
No skills, very violent. From the symbol bit exponent, the mantissa, the rounding, one by one. Note that float(x)
is the even rounding.
/*
* float_i2f - Return bit-level equivalent of expression (float) x
* Result is returned as unsigned int, but
* it is to be interpreted as the bit-level representation of a
* single-precision floating point values.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
unsigned float_i2f(int x) {
unsigned sign = x & (1 << 31);
unsigned exp = 0;
unsigned frac = 0;
unsigned round = 0;
unsigned absX = sign ? (~x + 1) : x;
unsigned tmp = absX;
while ((tmp = tmp >> 1))
++exp;
frac = absX << (31 - exp) << 1;
round = frac << 23 >> 23;
frac = frac >> 9;
if (round > 0x100) round = 1;
else if (round < 0x100) round = 0;
else round = frac & 1;
return x ? (sign | ((exp + 0x7F) << 23) | frac) + round : 0;
}
float_twice
Still very violent, according to a floating-point number to a classification: special value, returned directly; normalized floating-point number, order number plus 1; non-standardized, the left one and keep the sign bit unchanged.
/*
* float_twice - Return bit-level equivalent of expression 2*f for
* floating point argument f.
* Both the argument and result are passed as unsigned int's, but
* they are to be interpreted as the bit-level representation of
* single-precision floating point values.
* When argument is NaN, return argument
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
unsigned float_twice(unsigned uf) {
unsigned sign = 1 << 31;
unsigned isNormalized = uf << 1 >> 24;
unsigned isSpecial = isNormalized == 0xFF;
if (isSpecial || uf == 0 || uf == sign)
return uf;
if (isNormalized)
return uf + (1 << 23);
return (uf << 1) | (uf & sign);
}