標籤:語句 output including 負數 div val argument opera class
0.上手指南
一共 12 個需要補充的函數,所有的工作都只需修改 bits.c 檔案,測試的話有三種方式:btest, dlc, 和 BDD checker。
一些小技巧:
在函數開始時聲明所有變數
}應該在第一列
注意運算子號的優先順序,使用括弧確保順序的正確
關注 !, 0, TMin 等
任務指引還是比較清晰的,主要有以下一些說明:
整型的範圍是 0 到 255(0xFF),不允許用更大
只能包含參數和局部變數
一元操作符 ! ~
二元操作符 & | + << >>
不允許的操作有:
使用任何條件控制語句
定義和使用宏
定義其他的函數
調用函數
使用其他的操作符
使用類型轉換
使用除 int 之外的類型(針對整型)
使用除 int, unsigned 之外的類型(針對浮點數)
可以認為機器:
使用 2’s complent,32位
執行算術右移
移動超過字長的位元會出問題
其他需要注意的事情有:
使用 dlc(data lab checker) 來檢測代碼的合法性(有沒有使用不給使用的符號文法等等)
每個函數都有運算元的上限值,注意 = 不算
使用 btest 來測試結果的正確與否
使用 BDD checker 來正規測試你的函數
顯示32位int整型的show方法
void show(int x){ /* Show 32 Bits Integer By Binary */ for (int i = 0; i < 32; ++i) { if (i != 0 && i % 4 == 0) cout << " "; cout << ((x >> 31) & 1); x <<= 1; } cout << endl;}
該方法用於檢驗函數是否寫的正確以及調試的方便性
1.thirdBits
題目要求:return word with every third bit (starting from the LSB) set to 1
允許操作:! ~ & ^ | + << >>
運算元限制:8
分值:1
int thirdBits(){ /* Desired output: 0100 1001 0010 0100 1001 0010 0100 1001 step 1: 0000 0000 0000 0000 0000 0000 0100 1001 0x49 step 2: 0000 0000 0000 0000 1001 0010 0100 1001 step 3: 0000 0000 1001 0100 1001 0010 0100 1001 step 4: 0100 1001 0010 0100 1001 0010 0100 1001 */ int a = 0x49; int b = (a << 9); int c = a + b; return (c << 18) + c;}
2.isTmin
題目要求:returns 1 if x is the minimum, two’s complement number, and 0 otherwise
允許操作:! ~ & ^ | +
運算元限制:10
分值:1
該題用於檢驗INT_MIN 該題用到INT_MIN+INT_MIN溢出後為0的技巧 但也要注意0+0也為0
int isTmin(int x){ /* Return 1 if x is the minimum, two’s complement number, and 0 otherwise. */ return !(x + x) & !!(x);}
3.isNotEqual
題目要求:return 0 if x == y, and 1 otherwise
例如: isNotEqual(5,5) = 0, isNotEqual(4,5) = 1
允許操作:! ~ & ^ | + << >>
運算元限制:6
分值:2
該題用異或即可,不同則不為0,相同則0,隨後用到了!!將int值轉化為bool值的技巧
int isNotEqual(int x, int y){ /* Return 0 if x == y, and 1 otherwise */ return !!(x^y);}
4.anyOddBit
題目要求:return 1 if any odd-numbered bit in word set to 1
例如: anyOddBit(0x5) = 0, anyOddBit(0x7) = 1
允許操作:! ~ & ^ | + << >>
運算元限制:12
分值:2
該題的想法是想聲明一個值為0xaa的變數隨後將其擴充到32位,最後與x做與操作即可得到答案
int anyOddBit(int x){ /* Return 1 if any odd-numbered bit in word set to 1 1010 1010 */ int a = 0xAA; int b = (a << 8) + a; int c = (b << 8) + a; int d = (c << 8) + a; return !!(x&d);}
5.negate
題目要求:return -x
例如:negate(1) = -1.
允許操作:! ~ & ^ | + << >>
運算元限制:5
分值:2
該題利用補碼的取反後加一即可達到要求,但是最開始沒有想到取反操作而是製造了0xffffffff這個數進行操作
int negate(int x){ /* Return negate eg: if x==1 return -1 Or return ~x+1 */ int mask = (1 ^ (1 << 31)) >> 31; return (x^mask) + 1;}
6.conditional
題目要求:same as x ? y : z
例如:conditional(2,4,5) = 4
允許操作:! ~ & ^ | + << >>
運算元限制:16
分值:3
該題即三目操作符
int Conditional(int x, int y, int z){ /* x?y:z Better : int mask= ~!x+1; */ int mask = (!!x) << 31; mask >>= 31; return (mask&y) | ((~mask)&z);}
7.subOK
題目要求:Determine if can compute x-y without overflow
例如:
subOK(0x80000000,0x80000000) = 1
subOK(0x80000000,0x70000000) = 0
允許操作:! ~ & ^ | + << >>
運算元限制:20
分值:3
該題判斷減法是否溢出,減法是否溢出,第一個取決的便是兩個數位符號,我們可以發現
同號相減是不會溢出的,而異號相減溢出時結果的符號會與被減數的符號相反,所以有下面代碼
int subOK(int x, int y){ /* Determine if can compute x-y without overflow */ int a = (x >> 31) & 1; int b = (y >> 31) & 1; int res = x + ~y + 1; int c = (res >> 31) & 1; return !(a^b) | !(a^c);}
8.isGreater
題目要求:if x > y then return 1, else return 0
例如:isGreater(4,5) = 0, isGreater(5,4) = 1
允許操作:! ~ & ^ | + << >>
運算元限制:24
分值:3
該題比較兩個數位大小,首先我們明確正數是比負數大的,而負數比正數小
利用該性質我們可以先由該性質判斷,隨後利用兩數相減為正數時返回1性質寫出運算式
我們需要注意的是,該地方是不需要考慮溢出的,因為溢出是異號相減的行為
int isGreater(int x, int y){ /* if x > y then return 1, else return 0 */ int a = (x>>31) & 1, b = (y>>31) & 1; int res = x + ~y + 1; int c = (res>>31) & 1; return ((!a&b) | !c)&(!a | b);}
9.bitParity
題目要求:returns 1 if x contains an odd number of 0’s
例如:bitParity(5) = 0, bitParity(7) = 1
允許操作:! ~ & ^ | + << >>
運算元限制:20
分值:4
該題要我們數出一個int整形的二進位表達中是否有奇數個0,我們可以利用異或不改變奇偶性來寫
int bitParity(int x){ /* returns 1 if x contains an odd number of 0’s bitParity(5) = 0, bitParity(7) = 1 */ x = (x >> 16) ^ x; x = (x >> 8) ^ x; x = (x >> 4) ^ x; x = (x >> 2) ^ x; x = (x >> 1) ^ x; return (x & 1);}
10.howManyBits
題目要求:return the minimum number of bits required to represent x in two’s complement
例如:
howManyBits(12) = 5
howManyBits(298) = 10
howManyBits(-5) = 4
howManyBits(0) = 1
howManyBits(-1) = 1
howManyBits(0x80000000) = 32
允許操作:! ~ & ^ | + << >>
運算元限制:90
分值:4
該題要求我們返回該數字用補碼錶示時最少能用幾位來表示 我們可以用二分法來判斷有多少位
然後我們還要對特殊情況0和-1進行區分對待
值得一提的是,我們對負數要取反,但不必加一,因為補碼錶示中負數範圍是比正數大的
而最小的負數取反後剛剛好是最大的正數
int howManyBits(int x){ /* return the minimum number of bits required to represent x in two’s complement */ int a = ((!x) << 31) >> 31; //當x為0時,a全為1,否則全為0 int b = ((!~x) << 31) >> 31;//當x為-1時,b全為1,否則全為0 int bit_16, bit_8, bit_4, bit_2, bit_1; int sum; int op = x ^ (x >> 31); bit_16 = (!!(op >> 16)) << 4; op = op >> bit_16; bit_8 = (!!(op >> 8)) << 3; op = op >> bit_8; bit_4 = (!!(op >> 4)) << 2; op = op >> bit_4; bit_2 = (!!(op >> 2)) << 1; op = op >> bit_2; bit_1 = (!!(op >> 1)); op = op >> bit_1; sum = 2 + bit_16 + bit_8 + bit_4 + bit_2 + bit_1; return (a & 1) | (b & 1) | (~a & ~b&sum);}
11.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.
允許操作:Any integer/unsigned operations incl. ||, &&. also if, while
運算元限制:30
分值:4
該題只要懂得浮點數的表示即可寫出
unsigned float_i2f(int x){ int sign = (x >> 31) & 1; int exponent, fraction, fraction_mask = 0x7fffff; if (x == 0) return 0; else if (x == 0x8000000) exponent = 158; else { if (sign == 1) x = ~x + 1; int bit_16, bit_8, bit_4, bit_2, bit_1; int sum; int op = x ^ (x >> 31); bit_16 = (!!(op >> 16)) << 4; op = op >> bit_16; bit_8 = (!!(op >> 8)) << 3; op = op >> bit_8; bit_4 = (!!(op >> 4)) << 2; op = op >> bit_4; bit_2 = (!!(op >> 2)) << 1; op = op >> bit_2; bit_1 = (!!(op >> 1)); op = op >> bit_1; sum = 1 + bit_16 + bit_8 + bit_4 + bit_2 + bit_1; if (sum > 24) fraction = x >> (sum - 24); else if (sum < 24) fraction = x << (24 - sum); fraction &= fraction_mask; exponent = 127 + sum - 1; } show(fraction); unsigned ux = (sign << 31) + (exponent << 23) + fraction; return ux;}
12.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.
允許操作:Any integer/unsigned operations incl. ||, &&. also if, while
運算元限制:30
分值:4
該題是11題的逆過程,值得注意的是,我們要對小數部分進行切除
int float_f2i(float f){ int*pf = (int*)&f; int x = *pf; show(x); int sign = x >> 31; int x_abs = x & 0x7fffffff; int exponent = x_abs >> 23; if (exponent < 127) return 0; show(exponent); int fraction_mask = 0x7fffff; int fraction = x&fraction_mask; show(fraction); int i = 0; while (fraction) { if (fraction & 1) break; fraction >>= 1; ++i; } cout << i << endl; show(fraction); fraction |= (1 << (23 - i)); show(fraction); int len = exponent - 127 - (23 - i); cout << len << endl; int res; if (len > 0) res = fraction << len; else res = fraction >> -len; cout << exponent << endl; cout << res << endl; if (sign == -1) res = ~res + 1; return res;}
結語
第一個資料實驗算是結束了,通過該實驗,我又加深了對資料的理解,尤其是各種掩碼的設計,有了更深的理解
CSAPP實驗之Data Lab