contributed by potter903p
1
考慮以下程式碼 :
#include <stdlib.h>
int isMultN(unsigned int n) {
int odd_c = 0, even_c = 0; /* variables to count odd and even SET bits */
if (n == 0) // return true if difference is 0.
return 1;
if (n == 1) // return false if the difference is not 0.
return 0;
while (n) {
if (n & 1) // odd bit is SET, increment odd_C
odd_c++;
n >>= 1;
if (n & 1) // even bit is SET, increment even_c
even_c++;
n = n >> 1;
}
/* Recursive call till you get 0/1 */
return(isMultN(abs(odd_c - even_c)));
}
其作用為檢查輸入整數是否為 N 的倍數,那麼 N 為多少?
return(isMultN(abs(odd_c - even_c)));
得知唯有在 odd_c
等於 even_c
時程式才會判定為 N 的倍數。while
迴圈中第一個判斷式會判斷傳入數值之奇數位原的值為 1 或是 0 ,為 1 時將數值 odd_c
加 1 , 而第個二個判斷式則為偶數位原的相同判斷。這邊思考不夠周全,透過
e94046165
同學的筆記得知由於是遞迴呼叫,所以兩者之差值為 3 的倍數時均會成立,相比之前只有考慮到兩者數值相等應該思考輸入為多少時會回傳 1。
因此最後的結論為:偶數位原與奇數位原之差值為 3 的倍數
odd_c
以及 even_c
列出來做比較 :
延伸問題:
N = 5
#include <stdlib.h>
int isMultN(unsigned int n) {
int number = 0;
number = n & 1;
while(n > 0) {
n >>= 1;
number += (n & 1) * 2;
n >>= 1;
number += (n & 1) * 4;
n >>= 1;
number += (n & 1) * 8;
n >>= 1;
number += (n & 1) * 6;
}
if(number <= 15) {
return number == 15 ? 1 : number == 10 ? 1 : number == 5 ? 1 : 0;
}
return isMultN(number);
}
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
^ ^ ^ ^ ^
1 2 4 8 16
0000 0000 0000 0000 0000 0000 0000 0000 0000
^ ^ ^ ^
32 64 128 256
N = 7
2
考慮到下方函式 shift_right_arith
和 shift_right_logical
分別表示算術右移和邏輯右移,請嘗試補完程式碼。可由 sizeof(int) * 8
得知整數型態 int
的位元數 w
,而位移量 k
的有效範圍在 0 到 w - 1
。
#include <stdio.h>
int shift_right_arith(int x, int k) {
int xsrl = (unsigned) x >> k;
int w = sizeof(int) << P1;
int mask = (int) -1 << (P2);
if (x < 0)
return xsrl P3 mask;
return xsrl;
}
unsigned shift_right_logical(unsigned x, int k) {
unsigned xsra = (int) x >> k;
int w = sizeof(int) << P4;
int mask = (int) -1 << (P5);
return xsra P6 P7;
}
求 P1 ~ P7 的值?
首先要弄清楚 Arithmetic shift 和 Logical shift 之間的差異,兩者在 left shift 的操作是相同的都會在 LSB 端插入 0 , Arithmetic right shift 會在 MSB 端插入原本的 sign bit , logical right shift 則會在 MSB 端插入 0 。
P1
以及 P4
的數值皆為 3 (向左 shift 三位)。UINT_MAX + 1
(說明),更重要的是這會讓原本預計要執行 arithmetic right shift 的 signed value 變成執行 logicaL right shift 的 unsigned value ,因此對負數而言這樣轉換完會使得原本前面應該重複填入的 sign bit : 1 變成填入 0 ,因此我們要設法在 if(x < 0) 中做補救。P2
數值應為 w - k 而 P3
則為前述的 | 指令。P5
同樣是 w - k ,但由於是要清除 bits 的緣故,這邊的 mask 要變成 ~mask 然後再跟轉換完的數做 & 的操作,這樣才能在清除前面位元的情況下不改變後面後面位元的值,所以 P6
為 & ,P7
為 ~mask。延伸題目: 在 x86_64 和 Aarch32/Aarch64 找到對應的指令,並說明其作用和限制
3
考慮到某些實數的二進位表示形式如同 01
),而 0011
),考慮到以下 y 值,求出對應的十進位分數值。
010011
=> 101
=> 0110
=> 先來複習一下等比數列的定義:從第二項起,每一項與前一項的比都是一個常數。
以題目中的 01
)為例就可以把它看成是:
其實就是一個首項為
010011
101
0110