# 2019q3 Homework4 (compute-pi) contributed by < `93i7xo2` > ###### tags: `sysprog2019` Source: [2019q3 G06: compute-pi](https://hackmd.io/5C935B-JTLGAvHn0Zv-r5A?view) :::success ## 作業要求 - [x] 在 GitHub 上 fork [compute-pi](https://github.com/sysprog21/compute-pi),嘗試重現實驗,包含分析輸出 * 注意: 要增加圓周率計算過程中迭代的數量,否則時間太短就看不出差異 - [x] 閱讀 [error rate 分析](https://hackmd.io/@Ryspon/Hyd8pQPqx),並思考我們該留意 error rate - [ ] 用 gnuplot 作為 `$ make gencsv` 以外的輸出機制,預期執行 `$ make plot` 後,可透過 gnuplot 產生前述多種實做的效能分析比較圖表 - [ ] 可善用 [rayatracing](/s/B1W5AWza) 提到的 OpenMP, software pipelining, 以及 loop unrolling 一類的技巧來加速程式運作 - [ ] 詳閱前方 "Wall-clock time vs. CPU time",思考如何精準計算時間 - [x] 除了研究程式以外,請證明 [Leibniz formula for π](https://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80),並且找出其他計算圓周率的方法 - [ ] 思考如何不依賴 float 和 double 一類的浮點數型態來求圓周率,如 [不用函數庫和亂數 寫程式求 pi 值的方法](https://www.ptt.cc/bbs/Gossiping/M.1555612071.A.14C.html) - [ ] 留意精準度: [你不可不知道的 double 十件事](https://www.ptt.cc/bbs/b97902HW/M.1222953645.A.AE5.html) - [ ] 參照 [Bailey–Borwein–Plouffe formula](https://en.wikipedia.org/wiki/Bailey%E2%80%93Borwein%E2%80%93Plouffe_formula) - [ ] 將你的觀察、分析,以及各式效能改善過程,並善用 gnuplot 製圖,紀錄於「[2019q3 Homework4 (作業區)](https://hackmd.io/@sysprog/Bkb5cDMuH)」 --- 延伸思考: - clock(), clock_gettime() 的使用 - time(), gettimeofday() 的使用 - 為什麼 clock_gettime() 結果飄忽不定? - 為什麼 time() 和 gettimeofday() 不適合拿來作效能評比之用? ::: ## 實驗環境 ```bash! ~$ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian Address sizes: 39 bits physical, 48 bits virtual CPU(s): 8 On-line CPU(s) list: 0-7 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 94 Model name: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz Stepping: 3 CPU MHz: 802.054 CPU max MHz: 4000.0000 CPU min MHz: 800.0000 BogoMIPS: 6816.00 Virtualization: VT-x L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 8192K NUMA node0 CPU(s): 0-7 ~$ ldd --version ldd (Ubuntu GLIBC 2.29-3ubuntu1) 2.29 ~$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 19.04 Release: 19.04 Codename: disco ``` ## 重現實驗 [Error Rate]() 提及 loop=25 的實驗數值很不穩定,於是用 loop=250 重現實驗結果。 在 Makefile 裡, `plot` 這一段 rule 依賴 `gencsv` ,直接執行 `make plot` 產生圖片的同時一併產生測試數據 `result_clock_gettime.csv` 。 `METHOD ?=` 則用來指定計算方法,值為 BASELINE/LEIBNIZ/EULER 。 ### BASELINE Proof: 黎曼和 ```cpp= double compute_pi_baseline(size_t N) { double pi = 0.0; double dt = 1.0 / N; // dt = (b-a)/N, b = 1, a = 0 for (size_t i = 0; i < N; i++) { double x = (double) i / N; // x = ti = a+(b-a)*i/N = i/N pi += dt / (1.0 + x * x); // integrate 1/(1+x^2), i = 0....N } return pi * 4.0; } ``` ![](https://i.imgur.com/YSjqEwH.png) ![](https://i.imgur.com/fG49RXe.png) ### LEIBNIZ 證明參考 [Leibniz's Formula for Pi](https://proofwiki.org/wiki/Leibniz%27s_Formula_for_Pi)。從下面的 _Madhava–Leibniz series_ 開始推導: $$ arctan(1) = \dfrac{\pi}{4} = 1 - \dfrac{1}{3} + \dfrac{1}{5} - \dfrac{1}{7} +\ ... $$ 首先積分下列[數列](https://proofwiki.org/wiki/Leibniz%27s_Formula_for_Pi/Lemma) $$ \dfrac{1}{1+t^2} = 1 - t^2 + t^4 - t^6 + t^8 + ... + t^{4n} - \frac{t^{4n+2}}{1+t^2} $$ 從 $0$ 積分到 $x$, $0\leq{x}\leq1$ $$ \int_{0}^{x}\dfrac{1}{1+t^2}dt=x-\frac{x^3}{5}+\frac{x^5}{5}-\frac{x^7}{7}+...+\frac{x^{4n+1}}{4n+1}-R_n(x) \\where\ R_n(x)=\int_{0}^{x}\dfrac{t^{4n+2}}{1+t^2}dt $$ 先看 $R_n(x)$ ,因為 $1\leq1+t^2$,得到 $$ 0\leq{R_n(x)}\leq\int_{0}^{x}t^{4n+2}dt=\frac{x^{4n+3}}{4n+3} $$ 又因為 $$ \frac{x^{4n+3}}{4n+3}\leq\frac{1}{4n+3}, 0\leq{x}\leq1 $$ 依據夾擠定理(Squeeze Theorem),當 $n\rightarrow\infty, \frac{1}{4n+3}\rightarrow0$ ,於是得出下列式子 $$ \int_{0}^{x}\dfrac{1}{1+t^2}dt = x-\frac{x^3}{3}+\frac{x^5}{5}-\frac{x^7}{7}+\ ... $$ 而且$\frac{d}{dx}arctan(x)=\frac{1}{1+t^2}$ $$ arctan(x) = x-\frac{x^3}{3}+\frac{x^5}{5}-\frac{x^7}{7}+\ ... $$ $x$ 代入 1 即為欲求結果 ```cpp= double compute_pi_leibniz(size_t N) { double pi = 0.0; for (size_t i = 0; i < N; i++) { double tmp = (i & 1) ? (-1) : 1; pi += tmp / (2 * i + 1); } return pi * 4.0; } ``` ![](https://i.imgur.com/x4gz1oE.png) ![](https://i.imgur.com/9qsfIt1.png) ### EULER ```cpp= double compute_pi_euler(size_t N) { double pi = 0.0; for (size_t i = 1; i < N; i++) { pi += 1.0 / (i * i); } return sqrt(pi * 6); } ``` ![](https://i.imgur.com/c3PJNUO.png) ![](https://i.imgur.com/IaBauV4.png) ## Time function - clock() - clock_gettime() - time() - gettimeofday() ## Reference - [OpenMP](https://computing.llnl.gov/tutorials/openMP/) - [Ting19970 共筆](https://hackmd.io/ajtKm-SKTsOmQsUNegfk8g?view) - [uccuser159共筆](https://hackmd.io/@uccuser159/2019q3Homework4_computepi) - [Latex語法](https://zh.wikibooks.org/zh-tw/LaTeX/%E6%95%B0%E5%AD%A6%E5%85%AC%E5%BC%8F) - [簡單學 makefile:makefile 介紹與範例程式 ](https://mropengate.blogspot.com/2018/01/makefile.html)