Try   HackMD

contributed by <eleanorLYJ>

第 3 週測驗題

測驗 1 平方根

除了測驗題上的敘述,也閱讀Digit-by-digit calculation: Binary numeral system (base 2)

本筆記的變數的下標與作業說明順序相反

把 N 看為 某 bit pattern 的平方, 其中

ai 可能是
ai
或 0。我將
2i
想成 2 的冪的係數

N2=(a0+a1+a2+...+an)2

N=[a0a0a0a1a0a2...a0ana1a0a1a1a1a2...a1ana2a0a2a1a2a2...a2anana0ana1ana2...anan]
N2=a0a0+(a0a1+a1a0+a1a1)+(a0a2+a1a2+a2a2+a2a1+a2a0)+...+i=0n1j=n10aiaj=a02+(a1(a0+a1+a0))+(a2(a0+a1+a2+a1+a0))+...=a02+(a1(2a0+a1))+(a2(2a0+2a1+a2))+...+an[2i=0n1ai+an]

Pk=a0+a1+a2+..+ak=i=0kai


N2=a0+(a1(2P1+a1))+(a2(2P2+a2))+...+(an(Pn1+an))

Pm 會有兩種情況

Pm={Pm1+2m, if Pm2N2Pm, otherwise

這算 n~0 逐一算

N2Pm2,得知 m 等於多少時,使
Pm
值最接近
N

為了避免不要不斷的去算出

Pm2,所以改成僅存每一輪的差異,
Xm=N2Pm2

Xm 的更新為:
Xm=Xm1Ym

而 Y 的定義為上一輪的 P 與此輪的 P 的差異:
Ym=Pm2Pm12=2amPm1+am2

這裡的推導

Pm2=a02+a12+...am12+am2+2a0a1+...+2a0am1+2a0am+2a1am1+2a1amPm12=a02+a12+...am12+2a0a1+...+2a0am1+2a1am1Pm2Pm12=am2+2am(a0+...+am1)Ym=2amPm1+am2
接著在維基百科中說: 將
Ym
看成兩部分
cm
dm

cm=2amPm1dm=am2=(2m)2=22mYm={cm+dm,if am=2m0,if am=0

接著看如何迭代

Pm=Pm1+amcm1=2am1Pm2=cm2+dmdm1=am12=22(m1)=dm4Ym1={cm/2+dm,if am=2mcm/2,if am=0

以下程式的變數意義:

b =

ym =
Pm
-
Pm1

z =
cm

m =
dm

x =
Xm=N2Pm2

int i_sqrt(int x)
{
    if (x <= 1) /* Assume x is always positive */
        return x;

    int z = 0;
    for (int m = 1UL << ((31 - __builtin_clz(x)) & ~1UL); m; m >>= 2) {
        int b = z + m;
        z >>= 1;
        if (x >= b) 
            x -= b, z += m;               
    }
    return z;
}

測驗 3 ilog2()

用二分搜尋法尋找 Most Significant Bit (MSB)

static size_t ilog2(size_t i)
{
    size_t result = 0;
    while (i >= AAAA) {
        result += 16;
        i >>= 16;
    }
    while (i >= BBBB) {
        result += 8;
        i >>= 8;
    }
    while (i >= CCCC) {
        result += 4;
        i >>= 4;
    }
    while (i >= 2) {
        result += 1;
        i >>= 1;
    }
    return result;
}

測驗 5 ceil_log2

一開始的 x 減1 是為了確保結果向上進位到下一個整數。而 r 用於累加位移位元數。

該程式碼會迭代x多次,檢查特定的位元模式。它使用移位操作從中刪除已檢查的位元x。首先檢查最高位元 (MSB > 16),接著每次檢查的位元都除以2。 最終有考量最後 x 等於 2 或 3 的情況會進位,而最終 x 等於 1 時不會進位

int ceil_ilog2(uint32_t x)
{
    uint32_t r, shift;
    x--;
    r = (x > 0xFFFF) << 4;                               
    x >>= r;
    shift = (x > 0xFF) << 3;
    x >>= shift;
    r |= shift;
    shift = (x > 0xF) << 2;
    x >>= shift;
    r |= shift;
    shift = (x > 0x3) << 1;
    x >>= shift;
    return (r | shift | x > 1) + 1;       
}