Python 板


LINE

和上篇一樣,這篇是把計算圓周率π的程式照樣修改, 執行速度也快了兩倍多, 原本十億位需要 1 小時 28 分鐘,縮短到 40 分鐘 速度變快的關鍵主要出在三處: 1. mpfr.div() 原本寫錯了,應該要把整數的 mpz 轉成浮點數 mpfr 再除比較快, 我卻寫錯了,直接拿 mpz 去除,不知為何這樣會讓運算速度變得超級慢。 2. 寫檔時 write_string() 裡面有做排版,而這個排版的迴圈是一個字元一個字元 處理,速度非常的慢,我改成一次處理 50 個字元一行,速度就快了 50 倍。 3. 進度條處理得不好,不需更新進度時應該儘快 return,我卻做了多餘的 數學運算,多做一次當然沒什麼,多做七千萬次就有影響效能了。 這個 Divide and Conquer 的寫法很適合 multi-processing, 以及進度條可以改用 tqdm module,這些建議都不錯, 不過請體諒我才剛學 Python 沒幾天,需要點時間消化 (汗) 這次程式碼也放在 https://ideone.com/6YO1zU 方便大家複製貼上 #!/usr/bin/env python3 # # pi.py - Calculate Pi # import sys import time import math import gmpy2 from gmpy2 import mpfr from gmpy2 import mpz # # Global Variables # count = 0 total = 0 grad = 0 step = 0 # # Show Progress # def progress_init(max): global count, total, grad, step total = max count = 0 step = int(total / 1000) grad = int(step / 2) def progress(): global count, total, grad, step if (count > grad): grad += step g = int(math.floor(72.5*count/total+0.5)) p = int(math.floor(1000.5*count/total+0.5)) msg = "H" * g + "-" * (72-g) + " " + str(p/10) + "%\r" if (grad > total): msg += "\n" print(msg, sep="", end="", flush=True) # # Write digit string # def write_string(digit_string): fd = open("pi-py.txt", mode="w") fd.write(" pi = ") fd.write(digit_string[0]) fd.write(".") for c in range(1, len(digit_string), 50): if (c != 1): fd.write("\t") fd.write(digit_string[c:c+50]) if ((c % 1000) == 951): fd.write(" << ") fd.write(str(c+49)) fd.write("\r\n") elif ((c % 500) == 451): fd.write(" <\r\n") else: fd.write("\r\n") # Final new-line fd.write("\r\n") fd.close() # # Recursive funcion. # def s(a, b, max): global count m = math.ceil((a + b) / 2) if (b - a == 1): if (a == 0): r = 120 # 6! q = mpz(640320**3) p = gmpy2.sub( gmpy2.mul(q, 13591409), gmpy2.mul(r, 13591409+545140134) ) else: r = mpz(8 * (a*6+1) * (a*6+3) * (a*6+5)) q = mpz((b*640320)**3) if ((b%2) == 0): p = gmpy2.mul(mpz(13591409 + b*545140134), r) else: p = gmpy2.mul(mpz(-13591409 - b*545140134), r) else: p1, q1, r1 = s(a, m, max) p2, q2, r2 = s(m, b, max) # Merge p = gmpy2.add( gmpy2.mul(p1, q2), gmpy2.mul(p2, r1) ) q = gmpy2.mul(q1, q2) if (b != max): r = gmpy2.mul(r1, r2) else: r = 0 count += 1 progress() return p, q, r # # Calculate e # def calc_pi(digits): global total d = digits+1 n_terms = math.ceil(d*math.log(10)/(3*math.log(53360))) precision = math.ceil(d * math.log2(10)) + 4 print("d = ", d, ", n = ", n_terms, ", precision = ", precision, sep="") print("gmpy2 version:", gmpy2.version()) print("MP version:", gmpy2.mp_version()) print("MPFR version:", gmpy2.mpfr_version()) max_precision = gmpy2.get_max_precision() print("max_precision =", max_precision) max_emax = gmpy2.get_emax_max() print("max_emax =", max_emax) if (max_precision < precision): print("Error! Max precision is too small! Program terminated.") return gmpy2.get_context().precision = precision gmpy2.get_context().emax = max_emax print("Real precision = ", gmpy2.get_context().precision) progress_init(n_terms * 2 - 1) # Initialize progress bar # Recursion start_time = time.monotonic_ns() p, q, r = s(0, n_terms, n_terms) end_time = time.monotonic_ns() elapsed = (end_time - start_time) / 1000000000 print("Recursion:", elapsed, "seconds.") start_time = time.monotonic_ns() q = gmpy2.mul(q, 426880) end_time = time.monotonic_ns() elapsed = (end_time - start_time) / 1000000000 print("Multiply by 426880:", elapsed, "seconds.") start_time = time.monotonic_ns() pf = mpfr(p) qf = mpfr(q) ef = gmpy2.div(qf, pf) end_time = time.monotonic_ns() elapsed = (end_time - start_time) / 1000000000 print("Grand Division:", elapsed, "seconds.") start_time = time.monotonic_ns() ef = gmpy2.mul(ef, gmpy2.sqrt(10005)) end_time = time.monotonic_ns() elapsed = (end_time - start_time) / 1000000000 print("Multiply by sqrt(10005):", elapsed, "seconds.") # Convert to decimal digits start_time = time.monotonic_ns() estr, exp, prec = mpfr.digits(ef) estr = estr[0:d] end_time = time.monotonic_ns() elapsed = (end_time - start_time) / 1000000000 print("Convert to decimal digits:", elapsed, "seconds.") # Write to file start_time = time.monotonic_ns() write_string(estr) end_time = time.monotonic_ns() elapsed = (end_time - start_time) / 1000000000 print("Write to file:", elapsed, "seconds.") # # main program # if __name__ == '__main__': argc = len(sys.argv) if (argc >= 2): digits = int(sys.argv[1]) else: digits = 100000 calc_pi(digits) # End of pi.py -- 桃樂絲: 可是, 如果你沒有頭腦, 為什麼會說話? 稻草人: ㄝ, 我也不知... 但是有些人沒有頭腦也能說超~多話呢。 --



※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.165.64.143 (臺灣)
※ 文章網址: https://webptt.com/m.aspx?n=bbs/Python/M.1614281244.A.F7F.html
1F:推 idletime: 榨效能專用 03/06 23:06
雖說有聽人講過,用 Python 就不要太期待效能, 但這不妨礙我繼續追求更高的執行速度 最終能和 C 語言版差不多快也是始料未及...... ※ 編輯: Schottky (118.166.39.82 臺灣), 03/07/2021 09:16:36







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:WOW站內搜尋

TOP