Try   HackMD

2020q1 Homework2 (fibdrv)

contributed by < Hsuhaoxiang >

2020q1 表示 2020 年的第 1 季,即春季班課程的意思

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
jserv

自我檢查清單

  • 研讀上述 Linux 效能分析的提示 描述,在自己的實體電腦運作 GNU/Linux,做好必要的設定和準備工作
    從中也該理解為何不希望在虛擬機器中進行實驗;
  • 研讀上述費氏數列相關材料 (包含論文),摘錄關鍵手法,並思考 clz / ctz 一類的指令對 Fibonacci 數運算的幫助。請列出關鍵程式碼並解說
  • 複習 C 語言 數值系統bitwise operation,思考 Fibonacci 數快速計算演算法的實作中如何減少乘法運算的成本;
  • lsmod 的輸出結果有一欄名為 Used by,這是 "each module's use count and a list of referring modules",但如何實作出來呢?模組間的相依性和實際使用次數 (reference counting) 在 Linux 核心如何追蹤呢?
  • 注意到 fibdrv.c 存在著 DEFINE_MUTEX, mutex_trylock, mutex_init, mutex_unlock, mutex_destroy 等字樣,什麼場景中會需要呢?撰寫多執行緒的 userspace 程式來測試,觀察 Linux 核心模組若沒用到 mutex,到底會發生什麼問題

研讀上述費氏數列相關材料

費氏數列有公式解

an+1=an+bnbn+1=an
(anbn)=(1110)(a0b0)

方法是將前面的 Q-metrix 進行對角化,得到 eigenvalue
λ1=(1+52)
,
λ2=(152)

(anbn)=(1λ1λ2)(λ1λ211)(λ1n00λ2n)(1λ21λ1)(10)

a0=1
,
b0=0
最後寫成上式,將上面右式的矩陣乘開便得到
15(1+52)n15(152)n

  • 用的個公式算看似只需要常數時間便能求出答案,但其實浮點數的精確度是有限的,因此
    1±52
    的次方數越大就會有更大的誤差

Fast Doubling 手法

[F(2n+1)F(2n)]=[1110]2n[F(1)F(0)]=[1110]n[1110]n[F(1)F(0)]=[F(n+1)F(n)F(n)F(n1)][F(n+1)F(n)F(n)F(n1)][10]=[F(n+1)2+F(n)2F(n)F(n+1)+F(n1)F(n)]

因此可得:

F(2k)=F(k)[2F(k+1)F(k)]F(2k+1)=F(k+1)2+F(k)2
我們便可以由
F(k)
F(k+1)
算出
F(2k)
F(2K+1)
,需
O(logn)
次計算,但
F(50)
已經是 11 位數了,兩個大數相乘計算時間又會變得更長!

使用 Fast Doubling 加快計算費氏數列

  • 原本的寫法所花的時間為
    O(n)
static long long fib_sequence(long long k)
{
    long long f[k + 2];
    f[0] = 0;
    f[1] = 1;
    for (int i = 2; i <= k; i++) {
        f[i] = f[i - 1] + f[i - 2];
    }
    return f[k];
}
  • Fast doubling ,從 MSB 開始計算
    F(k)
    F(k+1)
    必須判斷目前的 bit 是否為 1,
    為了先算出他的二進位表示,我先跑了一次 while 同時算出他有幾位,這裡之後還要改成 clz / ctz 指令就不用先跑一次
    O(log(n))
static long long fib_fast_doub(long long k)
{
    int bin_k[10];
    int count = 0;
    while (k) {
        bin_k[count] = k % 2;
        k = k >> 1;
        count++;
    }
    long long int a = 0, b = 1;
    for (int i = count - 1; i >= 0; i--) {
        a = a * ((2 * b) - a);
        b = b * b + a * a;
        if (bin_k[i] == 1) {
            long long tmp;
            tmp = a + b;
            a = b;
            b = tmp;
        }
    }
    return a;
}
  • 在 user space 進行實驗並將實驗的數據以 gnuplot 繪製成圖表

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

在40項之後可以看出兩種演算法所花的時間差距會越來越大

增加
Fib(n)
的數值範圍

  • 因為超過 long long 所能表示的資料範圍就會溢位,原本的程式

    Fib(93)=6246583658587674878 必須更改儲存數值的方式

  • 目前正在參考 bignum 的做法


複習 C 語言 數值系統 和 bitwise operation,思考 Fibonacci 數快速計算演算法的實作中如何減少乘法運算的成本

  • 大數乘法可以用 Karatsuba 演算法加速