初等數學題解:求階乘的平方根

===》點我返回目錄《===

這個題目有點趣味,組合了前面兩個題目。

雖然內心有點疑惑,但是同古人同樣不辭辛勞的你把上面兩個題目的程序拼在一起:

n=int(input("enter a number:"))

result = 1

while n>1 :

    result = result * n

    n = n - 1

print (result)

n=result

if n>=0:

    y=n/2

    while y**2-n>0.0001 or y**2-n<-0.0001:

        y=(y+n/y)/2

    print(y)

else:

    print("Error: negative number")

運行結果,輸入10,結果輸出

3628800

1904.9409439665096

沒有錯。

雖然如此,你心裏還是覺得不對勁:計算機不應該這麼笨吧?它不能把以前寫的程序用某種方式複用一下嗎?

你的感覺是對的,有辦法的。而且這個辦法在程序出現的時候就有了,這就是Ada提出來的子過程的概念。我們可以把一段程序封裝成一個單獨的子過程,接受輸入,計算處理後,輸出結果,這個子過程可以被別的程序反覆調用。

Python裏面是這麼定義子過程的:

def functionname(p1,p2,...):

...

解釋一下,def關鍵字代表這裏要定義一個子過程,後面是子過程的名字,接下來的括號是參數(輸入值,數學上叫自變量)說明,後面過程代碼段。用return命令輸出結果(數學上叫做因變量)。

按照這個定義,我們先改寫階乘程序(factorial.py):

def factorial(n):

    result = 1

    while n>1 :

        result = result * n

        n = n - 1

    return result

print (factorial(10))

程序裏先用def定義一個叫做factorial的子過程,計算後return result。

使用這個子過程的代碼很簡單,直接調用factorial(10)。由於子程序是給人調用的,所以最後提供出來的時候要把print()語句去掉,否則會往屏幕上輸出結果。

同樣照此辦理,我們改寫牛頓逼近算法程序爲(sqrt.py):

def sqrt(n):

    if n>=0:

        y=n/2

        while y**2-n>0.000001 or y**2-n<-0.000001:

            y=(y+n/y)/2

        return y

    else:

        return -1

print (sqrt(10))

測試運行,表明新創建的sqrt()子過程也是對的。

注意這個子過程的實現,else裏面是return -1。以前我們對負數是屏幕輸出錯誤。但是子過程的目的是供別的程序調用,所以子過程自己不要這麼處理,返回一個永遠不可能的值(-1,不考慮複數),錯誤處理交給調用者。

以前調用exit退出程序,那個辦法不好,到現在我們看到了新的處理方法。

好,我們手頭現在有了這兩個子過程,我們這個題目就可以直接使用了。

一開頭,你大概會這麼編寫:

n=int(input("enter a number:"))

x = factorial(n)

y = sqrt(x)

print(y)

運行一下,出錯了:

NameError: name 'factorial' is not defined

計算機不知道這個factorial()子過程,同理也不知道sqrt()子過程。

可是,我們明明定義了啊。問題出在程序空間,本題的程序不能識別以前的題目編寫的程序,爲了識別,重用以前的程序,必須import一下。程序如下:

import factorial

import sqrt

n=int(input("enter a number:"))

x = factorial.factorial(n)

y = sqrt.sqrt(x)

print(y)

程序開始的兩行import了子過程程序文件,factorial.py和sqrt.py,這樣把以前編寫的程序引入了。調用的時候不直接寫子過程名字,而是在前面加了程序文件名,如factorial.factorial(),表示使用factorial這個程序裏的factorial子過程。

更加好的做法,是把相關的子過程寫在一個程序文件中,作爲一個函數包供大家調用。

我們可以這麼提供一個maths程序(maths.py):

#this is a mathematics library

#square root function

def sqrt(n):

    if n>=0:

        y=n/2

        while y**2-n>0.000001 or y**2-n<-0.000001:

            y=(y+n/y)/2

        return y

    else:

        return -1



#factorial function

def factorial(n):

    result = 1

    while n>1 :

        result = result * n

        n = n - 1

    return result

利用這個maths數學包,我們把本題的程序改寫爲:

import maths

n=int(input("enter a number:"))

x = maths.factorial(n)

y = maths.sqrt(x)

print(y)

好了,我們自己也可以寫庫了。其實,你也會想到,作爲一個應用面如此之廣的編程語言,Python不會不提供這些庫的。數學上常用的它都有,在math包中。你只要import math就可以了。

Python自帶的math包裏面常見的函數有:

向上取整

>>> math.ceil(4.12)

5

向下取整

>>> math.floor(4.9)

4

取整數

>>> math.trunc(6.789)

6

Cos餘弦

>>> math.cos(math.pi/4)

0.7071

Sin正弦

>>> math.sin(math.pi/4)

0.70710678

tan正切

>>> math.tan(math.pi/4)

0.99999

e的x次方

>>> math.exp(2)

7.389056

絕對值

>>> math.fabs(-0.03)

0.03

階乘

>>> math.factorial(4)

24

求和

>>> math.fsum((1,2,3,4))

10.0

最大公約數

>>> math.gcd(8,6)

2

以a爲底的對數返回。

>>> math.log(32,2)

5.0

平方根

>>> math.sqrt(100)

10.0

後面我們如果要用到類似的功能,就直接用Python自帶的math庫。

通過庫的概念,我們看到了,如何通過子過程複用和簡化問題。實際上,一個大一點的程序就是仔細分解子程序,最後通過某種結構將子程序組合在一起,積木式進行程序構建。最微型的原子子過程,組合成功能大一點的次小子過程,再進一步組合成大一些的子過程,這麼一級級分解組合。看起來程序像一臺機器,有很多組成部分,每一部分又分成許多部件,每一個部件又由許多零件組成。這樣就可以由專門的人負責專門的子過程了,大家的工作通過調用的參數和輸出關聯在一起,這種組織方式叫“軟件工程”。

我在這裏說得輕巧,其實“軟件工程”是相當複雜的事情,公認的看法,軟件開發是人類有史以來最複雜的工程任務。正是因爲這個原因,一個實際的軟件產品的開發是非常費時費力的,永遠在超期超預算同時質量沒有保證。《The Mythical Man-Month》(《人月神話》)這本名著也是偉大的技術專家Brooks自己項目失敗的經驗和教訓的總結。

文科生所把持的新聞媒體,一般喜歡傳奇的故事,會把事情說得神乎其神,一兩個天才在地下室或者車庫裏面埋頭半年一年功夫,發明了改變人類歷史的產品,這些神話不絕於耳。實際上你沒有看到幾個著名的公司是坐落在車庫裏的,它們仍然要組織成千上萬人做一款產品。一兩個天才是能想出改變歷史的點子來,然而要實現它,是需要無數人艱辛的努力的。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章