代碼:https://gitee.com/iwehdio/csapp-lab
1. bitXor
bitXor - x^y using only ~ and &
Example: bitXor(4, 5) = 1
Legal ops: ~ &
Max ops: 14
Rating: 1
- 異或,只能用~和&,操作數最大14個
int bitXor(int x, int y) {
int res = ~(~(x & ~y) & ~(~x & y));
return res;
}
- 思路
- 異或,就是不同時才為1,相同時為0。那么,使用非~就可以找出,x & y為1的位就是x為1但是y為0的位,x & y為1的位就是x為0但是y為1的位。
- 找出異或為1的位后,需要做一個或運算,但是本題中不能用|。用~(a | b)==~a & ~b來代替。
- 其他答案
int bitXor(int x, int y) {
return ~(~x&~y)&~(x&y);
}
- 這個利用的是,x&y為1的位是同時為0的,x&y為1的位是同時為1的,那么其按位非就是不同時為1且不同時為0的。
2. tmin
tmin - return minimum two's complement integer
Legal ops: ! ~ & ^ | + << >>
Max ops: 4
Rating: 1
- 2的補碼的最小值
int tmin(void) {
int res = 1 << 31;
return res;
}
- 只把符號位置為1就行了
3. isTmax
isTmax - returns 1 if x is the maximum, two's complement number, and 0 otherwise
Legal ops: ! ~ & ^ | +
Max ops: 10
Rating: 1
- 如果返回的是補碼的最大值,就返回1
int isTmax(int x) {
int addOne = x + 1;
int res = addOne ^ ~x;
return !(res + !addOne);
}
- 一個數的相反數的表示和這個數加一一樣,這種情況只存在於符號轉變的從-1到0和從TMax到TMin之間。排除0的情況就是TMax了
4. allOddBits
allOddBits - return 1 if all odd-numbered bits in word set to 1 where bits are numbered from 0 (least significant) to 31 (most significant)
Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
Legal ops: ! ~ & ^ | + << >>
Max ops: 12
Rating: 2
- 如果所有的奇數位都為1就返回1,位數是從零開始數的。
int allOddBits(int x) {
int mask = 0xAA;
mask |= mask << 8;
mask |= mask << 16;
int res = (x & mask) ^ mask;
return !res;
}
5. negate
negate - return -x
Example: negate(1) = -1.
Legal ops: ! ~ & ^ | + << >>
Max ops: 5
Rating: 2
- 返回負數
int negate(int x) {
int res = ~x + 1;
return res;
}
- 相反數就是補碼加一
6. isAsciiDigit
isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
Example: isAsciiDigit(0x35) = 1.
isAsciiDigit(0x3a) = 0.
isAsciiDigit(0x05) = 0.
Legal ops: ! ~ & ^ | + << >>
Max ops: 15
Rating: 3
- 返回數值在0x30和0x39之間的數
int isAsciiDigit(int x) {
int highBit = !((x >> 4) ^ 0x3);
int bitOne = (x>>3) & 0x1;
int bit23 = (x>>1) & 0x3;
return highBit & (!bitOne | !bit23);
}
- 0x30 → 0011 0000 0x39 → 0011 1001
- 在這個范圍內的,首先第一位必須是0011
- 其次第二位有兩種情況,最高位為0時,總是符合(0000~0111);最高位為1時,必須有中間兩位為0(1000,1001)
- 其他答案
- 可以使用兩個數,一個數是加上比0x39大的數后符號由正變負,另一個數是加上比0x30小的值時是負數。這兩個數是代碼中初始化的
upperBound和lowerBound,然后加法之后獲取其符號位判斷即可
- 可以使用兩個數,一個數是加上比0x39大的數后符號由正變負,另一個數是加上比0x30小的值時是負數。這兩個數是代碼中初始化的
int isAsciiDigit(int x) {
int sign = 0x1<<31;
int upperBound = ~(sign|0x39);
int lowerBound = ~0x30;
upperBound = sign&(upperBound+x)>>31;
lowerBound = sign&(lowerBound+1+x)>>31;
return !(upperBound|lowerBound);
}
7. conditional
conditional - same as x ? y : z
Example: conditional(2,4,5) = 4
Legal ops: ! ~ & ^ | + << >>
Max ops: 16
Rating: 3
- 實現一個三元表達式
int conditional(int x, int y, int z) {
int flag = ~!!x + 1;
return (flag & y) | (~flag & z);
}
- 把flag構造為全0或者全1的來與y和z進行與。
- 如果x非0,那么~!!x + 1就是全1;如果x是0,那么~!!x + 1就是全0
8. isLessOrEqual
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 = ~x + y + 1;
int signX = (x>>31) & 0x1;
int signY = (y>>31) & 0x1;
int signD = (diff>>31) & 0x1;
int sameSign = !(signX ^ signY);
return (sameSign & !signD) | (!sameSign & signX);
}
- 雖然不能用減法,但是比較大小就是做差的過程。轉換目標為y-x≥0,因為大於等於0的符號位都是0.
- 首先用y-x=~x+y+1算出差的位級表示,但是這個結果是可能溢出的,需要判斷是否溢出。
- 如果x和y的符號一致,肯定是不會溢出的;如果溢出的話,那么y-x≥0就取決於x和y的符號了(他倆一定是相反的)
9. logicalNeg
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
- 實現邏輯非的表示。
int logicalNeg(int x) {
int com = ~x + 1;
int signOrigin = (x>>31) & 0x1;
int signCom = (com>>31) & 0x1;
int sameSign = signOrigin ^ signCom ^ 0x1;
return sameSign & (((x>>31) & 0x1) ^ 0x1);
}
- 基本思路就是,既然只有一個輸入x,那么要么是對x進行變換后比較,要么是和固定值比較。
- 把x和-x的符號進行比較,如果不同那么就輸出0;如果相同且不是0x80000000就返回1。
- 主要是要用異或實現對指定位的非操作
- 其他答案
- 還是利用符號位,只不過要簡單一些。直接把x和-x的符號做或,如果為1就返回1,如果為0就返回0。使用右移31位,符號位為0就是0,符號位為1就是-1,加1即可
int logicalNeg(int x) {
return ((x|(~x+1))>>31)+1;
}
10. howManyBits
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
- 一個數用補碼表示最少需要幾位?
int howManyBits(int x) {
int sign = x>>31;
int y = (sign & ~x) | (~sign & x);
int b16 = (!!(y>>16))<<4; //高十六位是否有1
y = y>>b16; //如果有(至少需要16位),則將原數右移16位
int b8 = (!!(y>>8))<<3; //剩余位高8位是否有1
y = y>>b8; //如果有,則右移8位
int b4 = (!!(y>>4))<<2;
y = y>>b4;
int b2 = (!!(y>>2))<<1;
y = y>>b2;
int b1 = !!(y>>1);
y = y>>b1;
int b0 = y;
return b16 + b8 + b4 + b2 + b1 + b0 + 1;
}
- 位運算也不定不能用二分,這道題就相當於層層二分了。
- 對於正數,最少位數為最高位的1加一個符號位;對於負數,最少位數為最高位的0加一個符號位。所以可以直接把負數轉成補碼處理。
- 用兩個非!!來測試范圍內有沒有1,層層二分,如果范圍內有就位移並加上這個范圍。
11. floatScale2
floatScale2 - 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
- 求2乘以一個浮點數
unsigned floatScale2(unsigned uf) {
unsigned sign = uf >> 31;
unsigned exp = (uf >> 23) & 0xFF;
unsigned frac = uf & 0x7FFFFF;
if(exp==0xFF) {
return uf;
} else if(exp!=0) {
exp += 1;
} else {
if((frac>>22)&0x1) {
frac = frac & ~0x800000;
exp = 1;
}
frac = frac<<1;
}
return (sign<<31) | (exp<<23) | frac;
}
- 區分無窮/NaN,返回其本身。問題是其實無窮也應該返回NaN,但是直接返回無窮不會報錯。
- 規格化數直接exp加一;非規格化數如果最高位是1就要規格化。
12. floatFloat2Int
floatFloat2Int - 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
- 把浮點數轉換為整數
int floatFloat2Int(unsigned f) {
unsigned sign = f >> 31;
unsigned exp = (f >> 23) & 0xFF;
unsigned frac = f & 0x7FFFFF;
unsigned e, half, round, rest;
int k = 23;
int bias = 127;
if(exp==0xFF) {
return 0x80000000;
}
if(exp < bias) { //(1<<(8-1))-1
return 0;
} else {
frac |= 0x800000;
e = exp - bias;
if(e<k) {
half = 1<<(k - e - 1);
round = frac & ((1<<(k - e)) - 1);
rest = frac >> (k - e);
if(round>half) {
rest += 1;
} else {
if(round==half && (rest & 0x1)) {
rest += 1;
}
}
} else if(e<31) {
rest = frac << (e - k);
} else {
return 0x80000000;
}
}
if(sign) {
rest = ~rest + 1;
}
return rest;
}
- 比較麻煩的是處理向偶數舍入
13. floatPower2
floatPower2 - Return bit-level equivalent of the expression 2.0^x (2.0 raised to the power x) for any 32-bit integer x.
The unsigned value that is returned should have the identical bit representation as the single-precision floating-point number 2.0^x.
If the result is too small to be represented as a denorm, return 0. If too large, return +INF.
Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while
Max ops: 30
Rating: 4
- 輸入一個整數x,返回他的2x2^x2x
unsigned floatPower2(int x) {
int k = 23;
int bias = 127;
unsigned frac;
unsigned exp;
if(x>bias) {
return 0x7F800000;
} else if(x>=-bias) {
exp = x + bias;
frac = 0;
} else if(x>=-bias-k+2) {
exp = 0;
frac = 1<<(bias+k-2+x);
} else {
return 0x0;
}
return (exp<<k) | frac;
}
- 比較麻煩的是要處理非規格數。此外需要把超時時間調大一點,不然會運行不完。
