通過寫“猜數(shù)字”游戲?qū)W習(xí) Fortran
- Fortran 是在打孔卡時(shí)代編寫的語言,因此它的語法非常有限。但你仍然可以用它編寫有用和有趣的程序。
Fortran 77 是我學(xué)習(xí)的第一門編譯型編程語言。一開始時(shí),我自學(xué)了如何在 Apple II 上用 BASIC 編寫程序,后來又學(xué)會(huì)在 DOS 上用 QBasic 編寫程序。但是當(dāng)我去大學(xué)攻讀物理學(xué)時(shí),我又學(xué)習(xí)了 Fortran。
Fortran 曾經(jīng)在科學(xué)計(jì)算中很常見。曾幾何時(shí),所有計(jì)算機(jī)系統(tǒng)都有一個(gè) Fortran 編譯器。Fortran 曾經(jīng)像今天的 Python 一樣無處不在。因此,如果你是像我這樣的物理學(xué)專業(yè)學(xué)生,在 1990 年代工作,那你肯定學(xué)習(xí)了 Fortran。
我一直認(rèn)為 Fortran 與 BASIC 有點(diǎn)相似,所以每當(dāng)我需要編寫一個(gè)簡短程序,來分析實(shí)驗(yàn)室數(shù)據(jù)或執(zhí)行其他一些數(shù)值分析時(shí),我都會(huì)很快想到 Fortran。我在空閑時(shí)用 Fortran 編寫了一個(gè)“猜數(shù)字”游戲,其中計(jì)算機(jī)會(huì)在 1 到 100 之間選擇一個(gè)數(shù)字,并讓我猜這個(gè)數(shù)字。程序會(huì)一直循環(huán),直到我猜對了為止。
“猜數(shù)字”程序練習(xí)了編程語言中的幾個(gè)概念:如何為變量賦值、如何編寫語句以及如何執(zhí)行條件判斷和循環(huán)。這是學(xué)習(xí)新編程語言時(shí)一個(gè)很好的的實(shí)踐案例。
Fortran 編程基礎(chǔ)
雖然 Fortran 這些年來一直在更新,但我最熟悉的還是 Fortran 77,這是我多年前學(xué)習(xí)的實(shí)現(xiàn)版本。Fortran 是程序員還在打孔卡上編程的年代創(chuàng)建的,因此“經(jīng)典” Fortran 僅限于處理可以放在打孔卡上的數(shù)據(jù)。這意味著你只能編寫符合以下限制條件的經(jīng)典 Fortran 程序(LCTT 譯注:后來的 Fortran 95 等版本已經(jīng)對這些限制做了很大的改進(jìn),如有興趣建議直接學(xué)習(xí)新版):
- 每張卡只允許一行源代碼。
- 僅識(shí)別第 1-72 列(最后八列,73-80,保留給卡片分類器)。
- 行號(“標(biāo)簽”)位于第 1-5 列。
- 程序語句在第 7-72 列。
- 要表示跨行,請?jiān)诘?6 列中輸入一個(gè)連續(xù)字符(通常是 +)。
- 要?jiǎng)?chuàng)建注釋行,請?jiān)诘?1 列中輸入 C 或 *。
- 只有字符 A 到Z(大寫字母)、0 到9(數(shù)字)和特殊字符 = + - * / ( ) , . $ ' : 和空格能夠使用。
雖然有這些限制,你仍然可以編寫非常有用和有趣的程序。
在 Fortran 中猜數(shù)字
通過編寫“猜數(shù)字”游戲來探索 Fortran。這是我的實(shí)現(xiàn)代碼:
- CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
- C PROGRAM TO GUESS A NUMBER 1-100
- CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
- PROGRAM GUESSNUM
- INTEGER SEED, NUMBER, GUESS
- PRINT *, 'ENTER A RANDOM NUMBER SEED'
- READ *, SEED
- CALL SRAND(SEED)
- NUMBER = INT( RAND(0) * 100 + 1 )
- PRINT *, 'GUESS A NUMBER BETWEEN 1 AND 100'
- 10 READ *, GUESS
- IF (GUESS.LT.NUMBER) THEN
- PRINT *, 'TOO LOW'
- ELSE IF (GUESS.GT.NUMBER) THEN
- PRINT *, 'TOO HIGH'
- ENDIF
- IF (GUESS.NE.NUMBER) GOTO 10
- PRINT *, 'THATS RIGHT!'
- END
如果你熟悉其他編程語言,你大概可以通過閱讀源代碼來弄清楚這個(gè)程序在做什么。前三行是注釋塊,表示程序的功能。第四行 PROGRAM GUESSNUM 將其標(biāo)識(shí)為一個(gè) 程序program,并由最后一行的 END 語句關(guān)閉。
定義變量后,程序會(huì)提示用戶輸入隨機(jī)數(shù)種子。Fortran 程序無法從操作系統(tǒng)初始化隨機(jī)數(shù)生成器,因此你必須始終使用“種子”值和 SRAND 子程序subroutine 啟動(dòng)隨機(jī)數(shù)生成器。
Fortran 使用 RAND(0) 函數(shù)生成 0 到 0.999…… 之間的隨機(jī)數(shù)。參數(shù) 0 告訴 RAND 函數(shù)生成一個(gè)隨機(jī)數(shù)。將此隨機(jī)數(shù)乘以 100 以生成 0 到 99.999…… 之間的數(shù)字,然后加 1 得到 1 到 100.999…… 之間的值。INT 函數(shù)將結(jié)果截?cái)酁檎麛?shù);因此,變量 NUMBER 就是一個(gè)介于 1 到 100 之間的隨機(jī)數(shù)。
程序會(huì)給出提示,然后進(jìn)入一個(gè)循環(huán)。Fortran 不支持更現(xiàn)代的編程語言中可用的 while 或 do-while 循環(huán)(LCTT 譯注:Fortran 95 等新版支持,也因此在一定程度上減少了 GOTO 的使用)。相反,你必須使用標(biāo)簽(行號)和 GOTO 語句來構(gòu)建自己的循環(huán)。這就是 READ 語句有一個(gè)行號的原因:你可以在循環(huán)末尾使用 GOTO 跳轉(zhuǎn)到此標(biāo)簽。
穿孔卡片沒有 <(小于)和 >(大于)符號,因此 Fortran 采用了另一種語法來進(jìn)行值比較。要測試一個(gè)值是否小于另一個(gè)值,請使用 .LT.(小于)。要測試一個(gè)值是否大于另一個(gè)值,請使用 .GT.(大于)。等于和不等于分別是 .EQ. 和 .NE.。
在每次循環(huán)中,程序都會(huì)驗(yàn)證用戶的猜測值。如果用戶的猜測值小于隨機(jī)數(shù),程序打印 TOO LOW,如果猜測大于隨機(jī)數(shù),程序打印 TOO HIGH。循環(huán)會(huì)一直持續(xù),直到用戶的猜測值等于目標(biāo)隨機(jī)數(shù)為止。
當(dāng)循環(huán)退出時(shí),程序打印 THATS RIGHT! 并立即結(jié)束運(yùn)行。
- $ gfortran -Wall -o guess guess.f
- $ ./guess
- ENTER A RANDOM NUMBER SEED
- 93759
- GUESS A NUMBER BETWEEN 1 AND 100
- 50
- TOO LOW
- 80
- TOO HIGH
- 60
- TOO LOW
- 70
- TOO LOW
- 75
- TOO HIGH
- 73
- TOO LOW
- 74
- THATS RIGHT!
每次運(yùn)行程序時(shí),用戶都需要輸入不同的隨機(jī)數(shù)種子。如果你總是輸入相同的種子,程序給出的隨機(jī)數(shù)也會(huì)一直不變。
在其他語言中嘗試
在學(xué)習(xí)一門新的編程語言時(shí),這個(gè)“猜數(shù)字”游戲是一個(gè)很好的入門程序,因?yàn)樗苑浅:唵蔚姆绞骄毩?xí)了幾個(gè)常見的編程概念。通過用不同的編程語言實(shí)現(xiàn)這個(gè)簡單的游戲,你可以弄清一些核心概念以及比較每種語言的細(xì)節(jié)。
你有最喜歡的編程語言嗎?如何用你最喜歡的語言來編寫“猜數(shù)字”游戲?跟隨本系列文章來查看你可能感興趣的其他編程語言示例吧。