這里就不寫具體題目要求了,直接上代碼
// 不用 & 求 &
int bitAnd(int x, int y) {
return ~(~x | ~y);
}
// 提取第 n 字節(jié)
int getByte(int x, int n) {
// 就是移動 8 位的問題讲冠,8位就是 << 3
int a = n << 3;
return (x >> a) & 0xFF;
}
// 邏輯左移
int logicalShift(int x, int n) {
// x + ~x + 1 = 0
// -x = ~x + 1
// 31 - n = 31 + (~x + 1)
int k = 32 + (~n);
// 單純的左移會溢出体斩,<< n 其中 n 的值被定義為 0 到 31
// https://stackoverflow.com/questions/7401888/why-doesnt-left-bit-shift-for-32-bit-integers-work-as-expected-when-used
// 可以得到包括第 k 和高于第 k 的位為零其他位為 1
int a = (~0) + (1 << k);
// 再把第 k 位給加回來
a = a + (1 << k);
// 通過 & 把前面的 1 都干掉
return (x >> n) & a;
}
// 求 1 的個數(shù)
int bitCount(int x) {
// 分治法, 相當于把里面全部的 1 求和
// 那么分兩段,總 = (左 >> (位寬 / 2)) + 右
// 一直分到只有兩位,最后就相當于把所有的 1 都加起來
// 這里有個蛋疼的問題串纺,帶上 -O 優(yōu)化參數(shù),會使得編譯器會把超出 INT_MAX 的部分干掉
// https://stackoverflow.com/questions/47934277/why-does-clang-produces-wrong-results-for-my-c-code-compiled-with-o1-but-not-wi
// 0x5 = 0101
// 0x3 = 0011
// 0x0F = 0000 1111
// 0x00FF = 0000 0000 1111 1111
// 0x0000FFFF = 0000 0000 0000 0000 1111 1111 1111 1111
int mask1 = 0x55 | (0x55 << 8); // = 0x5555
mask1 = mask1 + (mask1 << 16); // = 0x5555 5555
int mask2 = 0x33 | (0x33 << 8); // = 0x3333
mask2 = mask2 | (mask2 << 16); // = 0x3333 3333
int mask3 = 0x0F | (0x0F << 8); // = 0x0F0F
mask3 = mask3 | (mask3 << 16); // = 0x0F0F 0F0F
int mask4 = 0xFF | (0xFF << 16); //= 0x00FF 00FF
int mask5 = 0xFF | (0xFF << 8); // = 0x0000 FFFF
int ans = (x & mask1) + ((x >> 1) & mask1);
ans = (ans & mask2) + ((ans >> 2) & mask2);
ans = (ans & mask3) + ((ans >> 4) & mask3);
ans = (ans & mask4) + ((ans >> 8) & mask4);
ans = (ans & mask5) + ((ans >> 16) & mask5);
return ans;
}
// 不用 !椰棘, 求 !
int bang(int x) {
// 非 0 的數(shù)字 x 和 -x 其中一個最高位也就是符號位是一定是 1
// 而 0 和 -0 最高位都是 0
// 確保得到最高位的數(shù)字 x | (-x)
int a = x | (~x + 1);
// 把最高位的數(shù)字移到最低位
int b = a >> 31;
// 取反纺棺,相當于對每一位求 !
int c = ~b;
// 把除最低位以外其他位都干掉
return c & 1;
}
// 最小 int
int tmin(void) {
return 1 << 31;
}
// 判斷 x 能否放進 n 位的空間里
int fitsBits(int x, int n) {
// 先左移到最高位,再右移回來邪狞,會自動獲得算術(shù)右移的結(jié)果
// 這樣得到的結(jié)果是相當于 n 位的補碼表示的數(shù)字
// 與 -x 相加最后得到 0 即為可以表示祷蝌,非零則無法表示
// 時刻記住 -x = ~x + 1
int k = 32 + (~n + 1);
return !(((x << k) >> k) + ~x + 1);
}
// x/(2^n)
int divpwr2(int x, int n) {
// 首先 x >> n 的自然結(jié)果是向下 round
// 也就是說 *不能被整除* 的 *負數(shù)* 得到結(jié)果后加 1 就可以
// 把最高位移下來可以得出是否為負數(shù)
int isXNegative = (x >> 31) & 1;
// 求得 x 的低 n 位是否為 0,是則能被整除外恕,否則不能被整除
int xNotDivisible = x & ~((1 << 31) >> (31 + ~n + 1));
// 通過兩次 ! 可以得到 0 或 1
return (x >> n) + (isXNegative & !!xNotDivisible);
}
// -x
int negate(int x) {
return ~x + 1;
}
// x 是否為正數(shù)
int isPositive(int x) {
// 首先最高位是 1 就是負數(shù)
// !操作就是說不是負數(shù)杆逗,但是 0 也不是正數(shù)乡翅,所以要排除
// x <> 0 時 !x = 0 且 !!x = 1
// 依舊是通過兩次 ! 得到一個 0 或者 1
return !((x >> 31) & 1) & !!x;
}
// x <= y
int isLessOrEqual(int x, int y) {
int isXNegative = (x >> 31) & 1;
int isYNegative = (y >> 31) & 1;
int isNegative = ((x + ~y + 1) >> 31) & 1;
int isZero = !(x + ~y + 1);
// 兩個數(shù)字符號不同時會有溢出可能鳞疲,但是符號不同時只有 x 為負數(shù)時返回 1
return ((isNegative | isZero) &
((isXNegative & isYNegative) |
(!isXNegative & !isYNegative))) |
(isXNegative & !isYNegative);
}
// return floor(log base 2 of x)
int ilog2(int x) {
// 問題可以轉(zhuǎn)化為 x 最高的 1 在哪個位置上,結(jié)果即為 0 到 31
// 這題蠕蚜,二分搜索尚洽?
int ans = 0;
// 搜索的條件如下
// 移動 16 如果說不等于 0 那么意味著高 16 位有 1,則答案至少為 16靶累,也就是 1 << 4
// 如果說等于 0 那么就在低 16 位
// 這個結(jié)果不僅代表數(shù)值還代表下一次搜索的位置
// 以此類推
ans = ans + ((!!(x >> (16 + ans))) << 4); // = 0 or = 16
ans = ans + ((!!(x >> (8 + ans))) << 3);
ans = ans + ((!!(x >> (4 + ans))) << 2);
ans = ans + ((!!(x >> (2 + ans))) << 1);
ans = ans + ((!!(x >> (1 + ans))) << 0);
return ans;
}
// 浮點符號反轉(zhuǎn)
unsigned float_neg(unsigned uf) {
unsigned k = uf & (0x7FFFFFFF);
if (k > 0x7f800000) {
return uf;
}
return uf + 0x80000000; // uf ^ 0x80000000 也可以
}
// int to float
unsigned float_i2f(int x) {
// 有些費勁腺毫,寫了很久,但其實理清思路并不是難挣柬,而是是否清晰的理解 IEEE 的浮點定義
// 首先 0 直接返回
// 接下來開始尋找最高的 1 在哪里潮酒,最高的一代表了指數(shù)
// 尾數(shù)是 23 位
// 注意到整數(shù)不會出現(xiàn)非規(guī)格數(shù),所以尾數(shù)中不需要最高位 1邪蛔,因為浮點的定義中尾數(shù)有隱含的 1
// 分為兩種情況:
// 指數(shù)小于等于 23急黎,左移至滿 23 位
// 指數(shù)大于 23,此時有舍入的問題,取最后所有位和移位后的最后一位勃教,axxx
// xxx 是會被干掉的部分淤击,注意此處不是限定三位,是后面所有位
// 向偶數(shù)舍入:
// a = 1 且 xxx = 100... 則入 1
// a = 0 且 xxx = 100... 則舍去
// xxx > 100... 時入 1
// xxx < 100... 時舍去
if (!x) return x;
// 提取符號并轉(zhuǎn)為正數(shù)
int isXNegative = (x >> 31) & 1;
int k = x;
if (isXNegative) {
k = ~x + 1; // -x
}
// 尋找最高位的 1
int e = 31;
int t = 0;
while (t == 0 && e >= 0) {
t = k & (1 << e);
e = e - 1;
}
// 得到指數(shù)
e = e + 1;
int low = 0;
// 尾數(shù) mask
int mask = ~((1 << 31) >> 8);
int needRound = 0;
if (e > 23) {
// 失去的位數(shù)
int lost = e - 23;
// 失去位的 mask
int fmask = mask >> (23 - lost);
// 舍入前的尾數(shù)
low = (k >> lost) & mask;
// 失去位的值
int f = k & fmask;
// 用于對比的正中間值故源,即 100...
int p = 1 << (lost - 1);
// 臨近失去位的一位值的mask
int lmask = 1 << lost;
// 臨近失去位的一位值
int l = k & lmask;
if (f > p) {// 失去位大于正中間污抬,入 1
needRound = 1;
} else if (f == p && l == lmask) {// 失去位在正中間,且前一位是奇數(shù)绳军,入 1
needRound = 1;
}
} else { // 右移或者不移動沒有舍入問題
low = (k << (23 - e)) & mask;
}
// 實際的階碼
e = (e + 127) << 23;
return (isXNegative << 31) + e + low + needRound;
}
// 乘 2
unsigned float_twice(unsigned uf) {
// 相對于上一道要簡單許多印机,按照 IEEE 的定義來計算即可
int t = 0x7F800000;
// 提取符號
int s = uf & 0x80000000;
// 提取階碼
int e = uf & t;
// 提取尾數(shù)
int f = uf & 0x007FFFFF;
// 原始賦值
int ans = uf;
// 非規(guī)格化情況
if (e == 0) {
// 符號 + 尾數(shù)左移一位
// 主要歸功于定義使得規(guī)格和非規(guī)格化之間可以平滑過渡
// 所以此處不需要擔(dān)心尾數(shù)移位直接進入階碼的情況
// 非規(guī)格化數(shù)的尾數(shù)左移移位至多使得階碼加一,剛剛好代表了同樣的意思
ans = s + (f << 1);
} else if (e != t) {
// 符號 + (階碼 + 1) + 尾數(shù)
ans = s + e + (1 << 23) + f;
}
// 如果是 NaN 或者 無窮大门驾,直接無視掉
return ans;
}