# 2018q3 Homework5 (bits)
contributed by <`krimson8`>
## 開發環境
```
gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 6
On-line CPU(s) list: 0-5
Thread(s) per core: 1
Core(s) per socket: 6
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 158
Model name: Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz
Stepping: 10
CPU MHz: 800.012
CPU max MHz: 4000.0000
CPU min MHz: 800.0000
BogoMIPS: 5616.00
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 9216K
NUMA node0 CPU(s): 0-5
```
## 安裝 32-bits 開發套件 與 遇到的問題
### 安裝
binutils g++-multilib
`sudo apt install libc6-dev:i386 gcc:i386 cpp-7:i386 g++-multilib`
其中 `cpp-7:i386` 是 `gcc:i386` 的 dependencies
### 遇到的問題
自 Ubuntu 17.10 開始便放棄自家的unity 桌面系統,改用 gnome 桌面系統,而 ubuntu 使用的gnome 是有特別訂製某些 interface 的,而安裝了上述的32 bits 開發套件過後會導致這些interface 不能用,進而導致桌面系統崩潰(連帶nvidia 的 driver 也一併崩潰)
### 解決方法
把上面安裝的套件逐一 purge 掉,然後 autoremove
再來
`sudo apt-get install --reinstall ubuntu-gnome-desktop`
nvidia 驅動部分也是 purge 掉重裝就好
## datalab
因爲實在衆多,只附上花了比較多時間思考的題目
### addOK
```clike=
int addOK(int x, int y)
{
unsigned temp_x = x;
unsigned temp_y = y;
int x_sign = (temp_x >> 31);
int y_sign = (temp_y >> 31);
int x_y_sign = ((temp_x + temp_y) >> 31);
return (((x_sign ^ y_sign) & 1) | (~((x_sign & y_sign) ^ x_y_sign) & 1));
}
```
套用一下真值表可推
|x|y|z|r|
|-|-|-|-|
|0|0|0|1|
|0|0|1|0|
|0|1|0|1|
|0|1|1|1|
|1|0|0|1|
|1|0|1|1|
|1|1|0|0|
|1|1|1|1|
`(x ^ y) | ~((x & y) ^ z )` 意義在於,x 和 y sign 不一樣的話一定成功,一樣的話則判斷加法過後 的 sign 有無變化,若不變則正確
### allEvenBits
```clike=
int allEvenBits(int x)
{
// first solution
/*
int p1 = (x >> 24) & 0xFF;
int p2 = (x >> 16) & 0xFF;
int p3 = (x >> 8) & 0xFF;
int p4 = x & 0xFF;
x = p1 & p2 & p3 & p4;
return !((x & 0x55) ^ 0x55);
*/
// second solution
x &= x >> 16;
x &= x >> 8;
x &= x >> 4;
x &= x >> 2;
return x & 1;
}
```
有想到兩種解法,第二種用的OP 較少
### bang
```clike=
int bang(int x)
{
x |= x >> 16;
x |= x >> 8;
x |= x >> 4;
x |= x >> 2;
x |= x >> 1;
return ~x & 1;
}
```
任一點爲一,則最後一bit 爲一,取最後一 bit 的not
### bitAnd
```clike=
int bitAnd(int x, int y)
{
// DeMorgan's Theorem (A x B)' = A' + B'
return ~(~x | ~y);
}
```
### bitMask
```clike=
int bitMask(int highbit, int lowbit)
{
int x = ~0; // 0xFFFFFFFF
int high = (x << highbit) << 1;
int low = x << lowbit;
return (high ^ low) & low;
}
```
左移highbit 和 lowbit 個 數量後,兩者差異的地方便是答案
### bitMatch
```clike=
int bitMatch(int x, int y)
{
// use solution in bitOr because "|" not available
// ~((~x) & (~y)) -- bitOr
return ~((~(x & y)) & (~(~x & ~y)));
}
```
做 XNOR
### bitParity
如課堂測驗所教
### bitXor
```clike=
int bitXor(int x, int y)
{
return ~((~(x & ~(x & y))) & (~(y & ~(x & y))));
}
```
凡是 or 和 and 的組合都可以參考下列網址
[nand logic](https://en.wikipedia.org/wiki/NAND_logic)
### byteSwap
```clike=
int byteSwap(int x, int n, int m)
{
n <<= 3;
m <<= 3;
int pn = (x >> n) & 0xFF;
int pm = (x >> m) & 0xFF;
x = x ^ (pn << n) ^ (pm << m);
return x | (pn << m) | (pm << n);
}
```
先提取出來,將那個地方清空(和自己 xor),在進行填空
### conditional
```clike=
int conditional(int x, int y, int z)
{
x |= x << 16;
x |= x << 8;
x |= x << 4;
x |= x << 2;
x |= x << 1;
x = x >> 30 >> 1; // sign extension
return (x & y) | (~x & z);
}
```
把 or 的結果集中在 sign bit,往右移extend 成 全0 或 全1
### distinctNegation
```clike=
int distinctNegation(int x)
{
// when x is 0 and 0x80000000(largest negative)
x = x << 1;
return !!(x);
}
```
### evenBits
```clike=
int evenBits(void)
{
int x = 0x55;
return x | (0x55 << 8) | (0x55 << 16) | (0x55 << 24);
}
```
不能使用超過 0cFF 的常數~~(好多同學都在用呢QQ)~~
### ezThreeFourths
```clike=
int ezThreeFourths(int x)
{
x += (x << 1);
return (x + ((x >> 30 >> 1) & 3)) >> 2;
}
```
先×3,如果結果是負數則 +3,在除2
### fitBits
```clike=
int fitsBits(int x, int n)
{
return !(((x >> (n + ~0)) + 1) >> 1);
}
```
參考同學的解答,先往右移 n-1 bit,考慮極端情況便是4 bit 的負數 往右移 3 bit,那還剩下 sign bit “1”,則加 1 再 往右移會導致結果不爲 0
### floatAbsVal
```clike=
unsigned floatAbsVal(unsigned uf)
{
unsigned exp = (uf >> 23) & 0xFF;
unsigned fraction = uf & 0x7FFFFF;
if (exp == 0xFF && fraction != 0) {
return uf;
}
return uf & 0x7FFFFFFF;
}
```
提取 exp 和 fraction ,根據NaN 的定義 return uf,否則移除sign bit 即可
### loatFloat2Int
```clike=
int floatFloat2Int(unsigned uf)
{
// value of float
// (-1) ^ S * 2 ^ (E - 127) * 1.fraction
unsigned sign = (uf >> 31) & 1;
int exp = ((uf >> 23) & 0xFF) - 127;
unsigned fraction = uf & 0x7FFFFF;
fraction |= 0x800000; // 補上 1,成爲1.XXX
if(exp < 0) {
return 0;
}
else if(exp > 31) {
return 0x80000000u;
}
// 23 bit of fraction 1.XX.......
// if exp < 23 because is already a unsigned, then must right shift
// right shift 23 - exp
// only if exp > 23 then left shift exp - 23(may be 0)
// if exp < 0 then 23 + abs(exp)
if(exp < 23) {
fraction >>= 23 - exp;
}
else if(exp > 23) {
fraction <<= exp - 23;
}
if(sign) {
fraction = ~fraction + 1;
}
return fraction;
}
```
參考程式碼內的註解
### floatIsEqual
```clike=
int floatIsEqual(unsigned uf, unsigned ug)
{
unsigned esf = uf & 0x7FFFFFFF; // exp + fraction
unsigned esg = ug & 0x7FFFFFFF;
// printf("f : %x -- g : %x\n", esf, esg);
if(!esf && !esg) {
return 1;
}
if(esf > 0x7F800000 || esg > 0x7F800000) {
return 0;
}
return uf == ug;
}
```
我在效能慢一點的筆電測試需要調整 btest 內的timeout value 至 20 才能成功,快一點的電腦也需要18 左右,看了很多同學的共筆貌似都有這個問題,但是實在想不到更快的方式了
### floatIsLess
```clike=
int floatIsLess(unsigned uf, unsigned ug)
{
int uf_sign = (uf >> 31) & 1;
int ug_sign = (ug >> 31) & 1;
int uf_exp = (uf >> 23) & 0xFF;
int ug_exp = (ug >> 23) & 0xFF;
int uf_frac = uf & 0x7FFFFF;
int ug_frac = ug & 0x7FFFFF;
unsigned esf = uf & 0x7FFFFFFF; // exp + fraction
unsigned esg = ug & 0x7FFFFFFF;
// printf("f : %x -- g : %x\n", uf_exp, ug_exp);
if(!esf && !esg) {
return 0;
}
if(esf > 0x7F800000 || esg > 0x7F800000) {
return 0;
}
if(uf_sign == ug_sign) {
if(uf_exp == ug_exp) {
if(uf_frac == ug_frac) {
return 0;
}
return (uf_frac < ug_frac) ^ uf_sign;
}
else {
return (uf_exp < ug_exp) ^ uf_sign;
}
}
else {
return uf_sign > ug_sign; // negative is 1 so > 0
}
return 0;
}
```
依次比較 sign,exp,fraction 即可,注意 sign 因爲 1 是負,所以判斷條件和另外兩個不一樣
### floatNegate
```clike=
unsigned floatNegate(unsigned uf)
{
unsigned esf = uf & 0x7FFFFFFF;
if(esf > 0x7F800000) return uf;
return uf ^ 0x80000000;
}
```
判斷 NaN 即可,然後吧sign bit 做negate
### floatPower2
```clike=
unsigned floatPower2(int x)
{
// bias = 127, 255 > 127 + x >= 0
if(x < -127) return 0;
if(x > 127) return 0x7F800000;
x += 127;
return x <<= 23;
}
```
這題想題目想了很久。。。fraction 是不會變的,只要調整exp 即可,因此 x + bias 然後放入 exp 的位子即可
### floatScale1d2
```clike=
unsigned floatScale1d2(unsigned uf)
{
unsigned esf = uf & 0x7FFFFFFF;
if(esf >= 0x7F800000) return uf;
int sign = uf & 0x80000000;
int exp = (uf >> 23) & 0xFF;
// printf("-- %x --%x\n", exp, uf);
if(exp > 1) { // bias=127, so exp<=0 right shift fraction
exp -= 1;
exp <<= 23;
return (uf &= 0x807FFFFF) | exp;
}
if((uf & 0x3) == 0x3) {
uf = uf + 0x2;
}
return ((uf >> 1) & 0x7fffff) | sign;
}
```
參考程式碼註解,exp > 1 則調整exp,小於 1 則注意舍入問題
### greatestBitsPos
```clike=
int greatestBitPos(int x)
{
x |= x >> 16;
x |= x >> 8;
x |= x >> 4;
x |= x >> 2;
x |= x >> 1;
// change the left side of most_significant bit to 1
// then right shift 1, and take the & result
// if x>= 0, sign bit = 0, no influence
// if x is neg, sign = 1, after ~x it becomes all 0
// thus ^ 0x80000000 to give the sign bit value 1
return x & ((~x >> 1) ^ 0x80000000);
}
```
參考程式碼註解
### implication
```clike=
int implication(int x, int y)
{
return (!x) | (x & y);
}
```
0 —> 0/1 都是對的,若 x 成立 則 y 必須成立,因此用and
:::info
持續更新中
:::