//P3 /* * isTmin - returns 1 if x is the minimum two's complement number, * and 0 otherwise * Legal ops: ! ~ & ^ | + */ intisTmin(int x) { // 1st Try: // Tmin = 0x80000000 // it should be !(x+x) & !!x // but int overflow is an ub... // I have to turn it to: return !(2 + ~x + ~x + !x); // // 2nd Try: // Tmin-1 = 0x7fffffff // Tmin ^ (Tmin-1) = 0xffffffff // ~0xffffffff = 0 // but minus is baned... // so i change it to: return !(~(x + (x + ~0)) + !x); // // 3rd Try: // ~Tmin+1 == Tmin // Tmin ^ (~Tmin+1) == 0
//P6 /* * leastBitPos - return a mask that marks the position of the least significant 1 bit. * Examples: leastBitPos(12) = 4 * leastBitPos(-2) = 2 * leastBitPos(0) = 0 * Legal ops: ! ~ & ^ | + << >> */ intleastBitPos(int x) { // what ~x+1 actually do is: // retain the LSB and ~all higher bits // e.g. 0000_1000b -> 1111_0111b -> 1111_1000b return x & (~x+1); }
题目需要保留最低位,然后把更高的位都置零。
突然发现 ~x+1 和这题十分契合:取反加一会保持最低有效位不变,而只把更高的位取反。因此 x & (~x+1) 就可以只留下最低有效位。
//P7 /* * byteSwap - swaps the nth byte and the mth byte * Examples: byteSwap(0x12345678, 1, 3) = 0x56341278 * byteSwap(0xDEADBEEF, 0, 2) = 0xDEEFBEAD * You may assume that 0 <= n <= 3, 0 <= m <= 3 * Legal ops: ! ~ & ^ | + << >> */ intbyteSwap(int x, int n, int m){ // 1. fetch two bits // 2. clear two bits // 3. assign two bits
int real_n, real_m, n_val, m_val;
real_n = n<<3; real_m = m<<3; n_val = (x >> real_n) & 0xFF; m_val = (x >> real_m) & 0xFF; x = x & ~(0xFF << real_m); x = x & ~(0xFF << real_n); x = x | (n_val << real_m); x = x | (m_val << real_n); return x; }
思路非常简单:
提取出两个待交换的字节
清除所在位置的值
把字节交换填入进去
注意到第 n 个Byte对应第 n*8 个bit,所以为了方便位移,起手就把n和m乘以8(左移3),放在real_n和real_m里面。 后面就是前面那三步。
P8 logicalShift
1 2 3 4 5 6 7 8 9 10 11
//P8 /* * 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: ! ~ & ^ | + << >> */ intlogicalShift(int x, int n) { int mask = ~(((1 << 31) >> n) << 1); return (x >> n) & mask; }
//P9 /* * isLessOrEqual - if x <= y then return 1, else return 0 * Example: isLessOrEqual(4,5) = 1. * Legal ops: ! ~ & ^ | + << >> */ intisLessOrEqual(int x, int y) { // (x <= y) == (x-y < 1) == (x + ~y < 0) // but I found that if number is too big(and while x*y<0), errors will happen // so I add the x0y and y0x so that the program can judge these special condition directly.
int xy, isxpos, isypos, x0y, noy0x;
xy = ((x+~y) >> 31) & 1; // normal x <= y judge isxpos = !(x>>31); isypos = !(y>>31); x0y = !isxpos & isypos; // x < 0 <= y noy0x = isypos | !isxpos; // !(y < 0 <= x) return (xy | x0y) & noy0x; }
//P10 /* * multFiveEighths - return floor(x*5/8), for 0 <= x, x is an integer * Example: multFiveEighths(10) = 6 * Legal ops: ! ~ & ^ | + << >> */ intmultFiveEighths(int x) { // normal form: ((x<<2)+x)>>3 // which is equal to ((x>>3)<<2)+(x>>3) // but when calc x>>3, the 3 least significant bits will be discard. // so i save them (xl3), and calc them seperately, and add the result together in the end.
int xl3, xd8; xl3 = x & 0x7; // x lowest 3 bits xd8 = x >> 3; // x divided by 8 return ((xd8<<2) + xd8) + (((xl3<<2) + xl3)>>3); }
//P11 /* * bitCount - returns count of number of 1's in word * Examples: bitCount(5) = 2, bitCount(7) = 3 * Legal ops: ! ~ & ^ | + << >> */ intbitCount(int x) { // reference: https://en.wikipedia.org/wiki/Hamming_weight int mask1, mask2, mask3;
// the simplest idea is to fetch every bit of x and add them together // but the point is to compress the operation into 40 ops // so let's do a bunch of add at the same time!
// // 2. do the operation x = (x & mask1) + ((x>>1) & mask1); x = (x & mask2) + ((x>>2) & mask2); //put count of each 4 bits into those 4 bits x = (x & mask3) + ((x>>4) & mask3); //put count of each 8 bits into those 8 bits x = x + (x >> 8 ); //put count of each 16 bits into their lowest 8 bits x = x + (x >> 16); //put count of each 32 bits into their lowest 8 bits
//P12 /* * greatestBitPos - return a mask that marks the position of the greatest significant 1 bit. * Example: greatestBitPos(12) = 8 * greatestBitPos(-2) = -2147483648 * greatestBitPos(0) = 0 * Legal ops: ! ~ & ^ | + << >> */ intgreatestBitPos(int x) { // The quiz is to mask off all bits except the MSB // Remove n lower bits: x = (x >> n) << n;
// For a uint_32: IF there is 1 in higher 16 bits, then we can throw the lower 16 bits, // For a uint_16: IF there is 1 in higher 8 bits, then we can throw the lower 8 bits, // For a uint_8: IF there is 1 in higher 4 bits, then we can throw the lower 4 bits, // For a uint_4: IF there is 1 in higher 2 bits, then we can throw the lower 2 bits, // For a uint_2: IF there is 1 in higher 1 bits, then we can throw the lower 1 bits.
int a1, a2, a3, a4, a5; int mask = (0xFF << 8) | 0xFF;
a1 = (!!(x>>16)) << 4; x = x >> a1; x = x & mask; // to tackle with extra 0xFFFFxxxx created by "Arithmetic Right Shift"
//P16 /* * 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 */ unsignedfloat_neg(unsigned uf) { unsigned exponent = uf & 0x7f800000; if ((exponent == 0x7f800000) && !!(uf & 0x7fffff)) return uf; elsereturn uf ^ 0x80000000; }
//P17 /* * 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 */ unsignedfloat_i2f(int x) { unsigned sign_bit = 0, exponent = 0, significand = 0; unsigned s_digits; // significant digits unsigned abs_x; unsigned carry;
if (x & 0x80000000) { x = -x; sign_bit = 0x80000000; } abs_x = x;
s_digits = 32; while (--s_digits && !(x & (1 << s_digits))) ; if (!s_digits) { if (x) return sign_bit | 0x3F800000; else return0; }
exponent = (s_digits + 127) << 23;
significand = abs_x << (32-s_digits); // remove highest bit carry = significand & 0x1FF; // part to be rounded significand = significand >> 9; if (carry >= 0x100) { if (carry > 0x100) // >100.. +1 significand += 1; else significand += significand & 1; // =100.. depend on significand & 1 if (significand & 0x800000) { exponent += 0x00800000; significand &= 0x7FFFFF; } }
//P18 /* * 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 */ unsignedfloat_twice(unsigned uf) { // turn uf into familiar format unsigned sign = uf & 0x80000000; unsigned exponent = uf & 0x7f800000; unsigned significand = uf & 0x7FFFFF;
if (exponent == 0x7f800000) return uf; // When argument is NaN, return argument; When argument is Inf, return Inf elseif (exponent == 0) // argument is denorm significand <<= 1; // significand *= 2 else exponent += 0x00800000; // argument is norm