Re: [問卦] 不用函數庫和亂數 寫程式求pi值的方法?
※ 引述《fragmentwing (片翼碎夢)》之銘言:
: 小弟程式設計新手
: 看到後面的講義習題要算圓周率
: 如果不用亂數,也不用函數庫的話
: 我自己用了一個在寫之前就覺得很浪費電腦能力的方法
: 在電腦能力處理極限,還沒法精確到小數點後第二位呢
: 鄉民會怎麼用程式求圓周率呢?
這裡提供一種途徑,只用到 C 語言標準函式庫裡頭的以下函式:
* fopen / fclose
* getc / putc
既然上述說要「浪費電腦能力」,那我們不妨試試這個策略:
a. 實作符合 Turing completeness (圖靈完備) 的 Brainfuck 程式語言 [1]
執行環境;
b. 撰寫 Brainfuck 程式,使其得以計算圓周率,並用十進位浮點數輸出;
可將 Brainfuck 的執行環境設想為一台機器,擁有一個讀寫頭及無限長的紙帶,
機器會依下列指令進行操作:
> : 使讀寫頭在紙帶上前進一格
< : 使讀寫頭在紙帶上後退一格
+ : 對目前讀寫頭下的值,進行遞增 1 的運算
- : 對目前讀寫頭下的值,進行遞減 1 的運算
. : 將目前讀寫頭下的值,以對應的字母輸出
, : 將目前讀寫頭下的字母讀入並轉為數字後寫回
[ : 比較目前的值,若不為 0 即前進,若為 0 就略過指令,直到遇上匹配的 ]
] : 比較目前的值,若不為 0,指令要跳回上個出現 [ 的位置
不難發現,作為一個「知易行難」的程式語言,Brainfuck 僅有 8 個指令,其中
2 個是 I/O 動作。作為 Turing machine 的實踐,Brainfuck 對記憶體單元作直接
存取,對應到 C 語言的概念來說,如果 char *p 指向記憶體區塊的話,Brainfuck
語言的 8 個指令可對照為以下 C 等價敘述:
Brainfuck C
--------- ---------
> ++p;
< --p;
+ ++*p;
- --*p;
. putchar(*p);
, *p = getchar();
[ while (*p) {
] }
也就是說,下方的 Brainfuck 程式碼:
+++++[-]
對應到 C 語言程式碼為:
*p = +5;
while (*p != 0) {
*p--;
}
既然有了指令對照表,我們即可著手建構小型的 Brainfuck 直譯器: (檔名為 bf.c)
#include <stdio.h>
#include <stdlib.h>
static int p[64 * 1024], d[1024 * 1024], r, t, e;
int main(int c, char *v[]) {
if (c < 2) exit(1);
for (FILE *f = fopen(v[1], "r"); f && (c = getc(f)) != EOF; p[r++] = c);
for (r = 0; (c = p[r]); r++) {
if (c == '>') t++;
if (c == '<') t--;
if (c == '+') d[t]++;
if (c == '-') d[t]--;
if (c == '.') putc(d[t], stdout);
for (e = 0; c == '[' && !d[t]; r++) {
if (p[r] == '[') e++;
if ((p[r] == ']') && (e-- == 1)) break;
}
for (; c == ']' && d[t]; r--) {
if (p[r] == ']') e++;
if ((p[r] == '[') && (e-- == 1)) break;
}
}
}
回到一開始提到的 Turing completeness,Brainfuck 與其說是程式語言,不如說是
一台理想機器的描述:機器具有無限的儲存 (storage,也就是無限長的紙帶)、運算
(arithmetic,如遞增和遞減)、條件判斷 ([ ] 涉及目前值是否為 0 的判斷) 以及
重複 (repetition,這也是 [ ] 的行為),Brainfuck 這台機器具備上述四項特徵,
是 Turing completeness。依據 Alan Turing 的觀點,這樣的一台機器,即可模擬
人類所能進行的任何計算過程,自然就包含圓周率的計算。
Felix Nawothnig 撰寫出可依據給定位數要求,計算並輸出十進位表示法的 Brainfuck
程式 [2],我略作調整,如下: (檔名為 pi.b)
> +++++ +++++ +++++ +++++ +++++ (25 digits)
[<+>>>>>>>>++++++++++<<<<<<<-]>+++++[<+++++++++>-]+>>>>>>+[<<+++[>>[-<]<[>]<-]>
>[>+>]<[<]>]>[[->>>>+<<<<]>>>+++>-]<[<<<<]<<<<<<<<+[->>>>>>>>>>>>[<+[->>>>+<<<<
]>>>>>]<<<<[>>>>>[<<<<+>>>>-]<<<<<-[<<++++++++++>>-]>>>[<<[<+<<+>>>-]<[>+<-]<++
<<+>>>>>>-]<<[-]<<-<[->>+<-[>>>]>[[<+>-]>+>>]<<<<<]>[-]>+<<<-[>>+<<-]<]<<<<+>>>
>>>>>[-]>[<<<+>>>-]<<++++++++++<[->>+<-[>>>]>[[<+>-]>+>>]<<<<<]>[-]>+>[<<+<+>>>
-]<<<<+<+>>[-[-[-[-[-[-[-[-[-<->[-<+<->>]]]]]]]]]]<[+++++[<<<++++++++<++++++++>
>>>-]<<<<+<->>>>[>+<<<+++++++++<->>>-]<<<<<[>>+<<-]+<[->-<]>[>>.<<<<[+.[-]]>>-]
>[>>.<<-]>[-]>[-]>>>[>>[<<<<<<<<+>>>>>>>>-]<<-]]>>[-]<<<[-]<<<<<<<<]++++++++++.
乍看鬼畫符的程式,注意到最後一個字元是 . (將目前讀寫頭下的值,以對應的字母輸出)
編譯 Brainfuck 直譯器並載入圓周率計算程式:
$ gcc -o bf bf.c
$ ./bf pi.b
在我的電腦 (AMD Ryzen Threadripper 2990WX 32-Core Processor, AMD 重返榮耀!) 搭配
Ubuntu Linux 18.04 LTS,執行時間約為 0.3 秒,ELF 執行檔約佔 6KB 空間。
參考執行輸出如下:
3.141592653589793238462643
若要提高圓周率計算的有效位數,那麼修改 pi.b 的第一行,把 + 指令的數量增加即可。
用雙手駕馭電腦的滋味,真是美妙 :-)
[1] brainf*ck: https://esolangs.org/wiki/brainfuck
[2] https://copy.sh/brainfuck/prog/yapi.b
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.116.246.163
※ 文章網址: https://www.ptt.cc/bbs/Gossiping/M.1555612071.A.14C.html
→
04/19 02:28,
5年前
, 1F
04/19 02:28, 1F
推
04/19 02:28,
5年前
, 2F
04/19 02:28, 2F
→
04/19 02:29,
5年前
, 3F
04/19 02:29, 3F
推
04/19 02:29,
5年前
, 4F
04/19 02:29, 4F
推
04/19 02:30,
5年前
, 5F
04/19 02:30, 5F
推
04/19 02:30,
5年前
, 6F
04/19 02:30, 6F
推
04/19 02:31,
5年前
, 7F
04/19 02:31, 7F
→
04/19 02:33,
5年前
, 8F
04/19 02:33, 8F
推
04/19 02:33,
5年前
, 9F
04/19 02:33, 9F
推
04/19 02:33,
5年前
, 10F
04/19 02:33, 10F
→
04/19 02:34,
5年前
, 11F
04/19 02:34, 11F
推
04/19 02:35,
5年前
, 12F
04/19 02:35, 12F
推
04/19 02:39,
5年前
, 13F
04/19 02:39, 13F
推
04/19 02:42,
5年前
, 14F
04/19 02:42, 14F
推
04/19 02:42,
5年前
, 15F
04/19 02:42, 15F
→
04/19 02:43,
5年前
, 16F
04/19 02:43, 16F
推
04/19 02:45,
5年前
, 17F
04/19 02:45, 17F
推
04/19 02:45,
5年前
, 18F
04/19 02:45, 18F
推
04/19 02:46,
5年前
, 19F
04/19 02:46, 19F
→
04/19 02:47,
5年前
, 20F
04/19 02:47, 20F
→
04/19 02:50,
5年前
, 21F
04/19 02:50, 21F
推
04/19 02:51,
5年前
, 22F
04/19 02:51, 22F
推
04/19 02:54,
5年前
, 23F
04/19 02:54, 23F
推
04/19 02:55,
5年前
, 24F
04/19 02:55, 24F
→
04/19 02:56,
5年前
, 25F
04/19 02:56, 25F
→
04/19 02:56,
5年前
, 26F
04/19 02:56, 26F
推
04/19 02:57,
5年前
, 27F
04/19 02:57, 27F
→
04/19 02:58,
5年前
, 28F
04/19 02:58, 28F
推
04/19 03:01,
5年前
, 29F
04/19 03:01, 29F
推
04/19 03:01,
5年前
, 30F
04/19 03:01, 30F
推
04/19 03:03,
5年前
, 31F
04/19 03:03, 31F
→
04/19 03:03,
5年前
, 32F
04/19 03:03, 32F
推
04/19 03:04,
5年前
, 33F
04/19 03:04, 33F
推
04/19 03:05,
5年前
, 34F
04/19 03:05, 34F
推
04/19 03:05,
5年前
, 35F
04/19 03:05, 35F
推
04/19 03:07,
5年前
, 36F
04/19 03:07, 36F
推
04/19 03:10,
5年前
, 37F
04/19 03:10, 37F
推
04/19 03:10,
5年前
, 38F
04/19 03:10, 38F
推
04/19 03:12,
5年前
, 39F
04/19 03:12, 39F
還有 166 則推文
推
04/19 16:19,
5年前
, 206F
04/19 16:19, 206F
推
04/19 17:24,
5年前
, 207F
04/19 17:24, 207F
推
04/19 17:31,
5年前
, 208F
04/19 17:31, 208F
噓
04/19 17:35,
5年前
, 209F
04/19 17:35, 209F
推
04/19 19:03,
5年前
, 210F
04/19 19:03, 210F
→
04/19 19:08,
5年前
, 211F
04/19 19:08, 211F
推
04/19 20:24,
5年前
, 212F
04/19 20:24, 212F
推
04/19 20:48,
5年前
, 213F
04/19 20:48, 213F
推
04/19 20:54,
5年前
, 214F
04/19 20:54, 214F
推
04/19 22:16,
5年前
, 215F
04/19 22:16, 215F
推
04/19 23:17,
5年前
, 216F
04/19 23:17, 216F
推
04/20 00:57,
5年前
, 217F
04/20 00:57, 217F
推
04/20 01:40,
5年前
, 218F
04/20 01:40, 218F
推
04/20 02:17,
5年前
, 219F
04/20 02:17, 219F
推
04/20 06:10,
5年前
, 220F
04/20 06:10, 220F
→
04/20 09:18,
5年前
, 221F
04/20 09:18, 221F
→
04/20 09:18,
5年前
, 222F
04/20 09:18, 222F
→
04/20 09:19,
5年前
, 223F
04/20 09:19, 223F
→
04/20 09:19,
5年前
, 224F
04/20 09:19, 224F
→
04/20 09:20,
5年前
, 225F
04/20 09:20, 225F
→
04/20 09:21,
5年前
, 226F
04/20 09:21, 226F
→
04/20 09:25,
5年前
, 227F
04/20 09:25, 227F
→
04/20 09:26,
5年前
, 228F
04/20 09:26, 228F
→
04/20 09:27,
5年前
, 229F
04/20 09:27, 229F
→
04/20 09:28,
5年前
, 230F
04/20 09:28, 230F
推
04/20 09:55,
5年前
, 231F
04/20 09:55, 231F
推
04/20 10:16,
5年前
, 232F
04/20 10:16, 232F
→
04/20 16:27,
5年前
, 233F
04/20 16:27, 233F
→
04/20 16:28,
5年前
, 234F
04/20 16:28, 234F
→
04/20 16:29,
5年前
, 235F
04/20 16:29, 235F
→
04/20 16:29,
5年前
, 236F
04/20 16:29, 236F
推
04/20 22:50,
5年前
, 237F
04/20 22:50, 237F
→
04/22 05:59,
5年前
, 238F
04/22 05:59, 238F
→
04/22 08:40,
5年前
, 239F
04/22 08:40, 239F
→
04/22 10:19,
5年前
, 240F
04/22 10:19, 240F
推
05/06 12:52,
5年前
, 241F
05/06 12:52, 241F
推
09/12 15:04,
4年前
, 242F
09/12 15:04, 242F
→
09/12 15:04,
4年前
, 243F
09/12 15:04, 243F
→
09/12 15:04,
4年前
, 244F
09/12 15:04, 244F
推
04/26 16:54,
4年前
, 245F
04/26 16:54, 245F
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 3 之 4 篇):