/* * 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: ! ~ & ^ | + << >> * Max ops: 25 * Rating: 2 */ intbyteSwap(int x, int n, int m) { /** * first get the bytes needed to swap: n_byte and m_byte, which * seperately present nth byte of x and mth byte of y. * then set y = n_byte ^ m_byte. * because y ^ n_byte = n_byte ^ m_byte ^ n_byte = m_byte, * same as y ^ m_byte, so x ^= y << n will set nth byte to m_byte, * and x ^= y << m will set mth byte to n_byte. */ int y = 0; n = n << 3; m = m << 3; y = 0xff & ((x >> n) ^ (x >> m)); x = x ^ (y << n); x = x ^ (y << m); return x; }
/* * rotateRight - Rotate x to the right by n * Can assume that 0 <= n <= 31 * Examples: rotateRight(0x87654321,4) = 0x18765432 * Legal ops: ~ & ^ | + << >> ! * Max ops: 25 * Rating: 3 */ introtateRight(int x, int n) { /** * x >> n presents the lower n bits, and (x ^ (x >> 31)) << * (31 ^ n) << 1 presents the higher 32 - n bits. In order to * clean the 1 generated by moving right, you can XOR the sign of * x.It's x ^ (x >> 31) */ return (x >> n) ^ ((x ^ (x >> 31)) << (31 ^ n) << 1); }
/* * logicalNeg - implement the ! operator, using all of * the legal operators except ! * Examples: logicalNeg(3) = 0, logicalNeg(0) = 1 * Legal ops: ~ & ^ | + << >> * Max ops: 12 * Rating: 4 */ intlogicalNeg(int x) { /** * If x == 0, then negX | x >> 31 = 0, * else it must be -1, so add 1 to the result is * the final answer. */ return (((~x + 1) | x) >> 31) + 1; }
/* * isGreater - if x > y then return 1, else return 0 * Example: isGreater(4,5) = 0, isGreater(5,4) = 1 * Legal ops: ! ~ & ^ | + << >> * Max ops: 24 * Rating: 3 */ intisGreater(int x, int y) { /** * first, we can get the average of x and y with no overflow happening * by using the expression: (x & y) + (x ^ y) >> 1. * Ideas as follows: * for these bits which are both 1 in x and y, then bits_x & bits_y = average() * eg: bits_x = 0100, bits_y = 0100, then average = bits_x & bits_y = 0100 * for other bits, to get their average, we can use (bits_x ^ bits_y)>>1. * eg: bits_x = 0100 = 4, bits_y = 0010 = 2, then average = (0110)>>1 = 0011 = 3 * So if we want to get the average of x and y, we can separate x and y to * the two conditions above and deal with them with certain operator, then * add them to get the correct result. Because this operation won't generate carrying, * so the result won't overflow. * * In addition, because the sign of x - y and (x - y)/2 are the same, so we can * get the sign of average(x , ~y), when x > y, the sign is 0, else sign is 1, * so the result is !sign. * */ y = ~y; return !(((x & y) + ((x ^ y) >> 1)) >> 31); }
/* * satAdd - adds two numbers but when positive overflow occurs, returns * maximum possible value, and when negative overflow occurs, * it returns minimum positive value. * Examples: satAdd(0x40000000,0x40000000) = 0x7fffffff * satAdd(0x80000000,0xffffffff) = 0x80000000 * Legal ops: ! ~ & ^ | + << >> * Max ops: 30 * Rating: 4 */ intsatAdd(int x, int y) { /** * if x + y overflow, then sum has different sign with x and y. * so if overflow, the value overFlow will be -1, overwise 0. * * In this case, if pos + pos = neg, then overFlow << 31 will be * 0x80000000, and sum >> overFlow will be 0xfffffffff, and both XOR * will be 0x7fffffff. Same if neg + neg = pos. * * If not overflow, overFlow << 31 is always 0, and sum >> overFlow is still * sum. So the result is not changed. */ int sum = x + y; int overFlow = ((sum ^ x) & (sum ^ y)) >> 31; return (sum >> overFlow) ^ (overFlow << 31); }
/* howManyBits - return the minimum number of bits required to represent x in * two's complement * Examples: howManyBits(12) = 5 * howManyBits(298) = 10 * howManyBits(-5) = 4 * howManyBits(0) = 1 * howManyBits(-1) = 1 * howManyBits(0x80000000) = 32 * Legal ops: ! ~ & ^ | + << >> * Max ops: 90 * Rating: 4 */ inthowManyBits(int x) { /** * To get the minimum bits needed by x, just get the first '1' * from high bit to low bit of x if x > 0 or ~x if x < 0. * * The main idea is binary search, first check the high 16 bits. * If it's not 0, then x must >= 2^16, else x must < 2^16. Record * 16 in value. * then check the high 8 bits in the none zero zone of x. Loop * until the high 1 bit. Finally add all of the recorded values and the * sign bit to get the result. * */ int b16, b8, b4, b2, b1, b0; int sign = x >> 31; x ^= sign;
b16 = !!(x >> 16) << 4; x = x >> b16; b8 = !!(x >> 8) << 3; x = x >> b8; b4 = !!(x >> 4) << 2; x = x >> b4; b2 = !!(x >> 2) << 1; x = x >> b2; b1 = (x >> 1); x = x >> b1; b0 = x; return b16 + b8 + b4 + b2 + b1 + b0 + 1; }
/* * float_half - Return bit-level equivalent of expression 0.5*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 */ unsignedfloat_half(unsigned uf) { /** * first get sign, exp digit and check if uf need to round off. * if uf = inf or nan, return uf * if exp = 0 or exp = 1, as well as uf is 0 or not format digit or * exp = 1, move left the addition of tail digit and the round bit. * and finally add the sign bit. * In other cases, DEC exp digit. */ unsignedexp = uf & 0xff800000; unsigned frac; unsigned mask = 0x7fffff; unsigned shift = 1;
return sign_exp | frac; } /* * float_f2i - Return bit-level equivalent of expression (int) f * for floating point argument f. * Argument is passed as unsigned int, but * it is to be interpreted as the bit-level representation of a * single-precision floating point value. * Anything out of range (including NaN and infinity) should return * 0x80000000u. * Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while * Max ops: 30 * Rating: 4 */ intfloat_f2i(unsigned uf) { /** * first get sign, exp and frac digit, then check if uf is over the range of * unsigned int and return the certain value. * If not, add the hidden bit and move left frac by 7 bit so that every bit * won't lose even if the right steps of movement is maxinum -- 30. * Finally, return the result according the correct sign. */ int sign = uf >> 31; intexp = (uf >> 23) & 0xff; int frac = uf & 0x007fffff; int right = 157 - exp; intabs; if (exp < 127) return0; if (exp > 157) return0x80000000; abs = (0x40000000 + (frac << 7)) >> right; if (sign) return -abs; else returnabs; } /* * 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 */ unsignedfloat_twice(unsigned uf) { /** * first get exp and sign of uf, if exp is not 0, INC when exp is also * not 255. * else, it indicates that uf is 0 or not format digit, just double its * frac and return the result according the correct sign. */ unsignedexp = uf & 0x7f800000; unsigned sign = uf & 0x80000000; if (exp) { if (exp != 0x7f800000) uf = uf + 0x00800000; } else uf = (uf << 1) | sign; return uf; }