2024-08-11|閱讀時間 ‧ 約 7 分鐘

如果 高斯 小時候學過python,會怎麼用程式計算 1+2+3+...+100?

前言

相傳有一個故事,
數學家高斯的小學數學老師出了一道從1+2+3+...+100的習題,
想讓活潑好動的小學生們算一整節課,消耗一下多餘的體力,
結果老師剛說完題目沒過多久,小高斯就算出了答案。

原來,他發現數列兩端可以兩兩配對:1+100,2+99……每一對的和都是101,共有50對,所以總和是5050。讓老師讚嘆不已,也讓老師對這個與眾不同的小高斯刮目相看。


如果 高斯 小時候學過python,會怎麼用python程式來計算 1+2+3+...+100?


先回到故事的起點,小高斯可能會這樣寫:


根據1+2+3+...+100的對稱性,小高斯推導出

數列和 = (首項 + 末項) * 項數 / 2

def range_sum(start, end):

n = end - start + 1
summation = (start + end) * n // 2

return summation

print( range_sum(start=1, end=100) )

輸出結果

5050

但是小高斯求知若渴,不滿足於此,他想試試看Python可以有多少種不同的實作方式,來算出1+2+3+...+100的和。


根據小高斯學過C/C++的經驗,很快想出python對應的

for loop based 迭代寫法

def range_sum(start, end):

summation = 0
for i in range(start, end+1):
summation += i

return summation

print( range_sum(1, 100) )

輸出結果

5050


然後,思索片刻,小高斯又想到數學老師說,
迭代和遞迴往往彼此擁有等價互通的寫法。又寫出了對應的

遞迴形式解

def range_sum(start, end):

if start == end:
return start
else:
return range_sum(start, end-1) + end

print( range_sum(1, 100) )

輸出結果

5050


這時候,他又想起電腦老師教過python特有的list comprehension列表生程式,
寫起來乾淨又清爽。

list comprehension列表生程式

def range_sum(start, end):

numbers = [ i for i in range(start, end+1) ]
return sum( numbers )

print( range_sum(1, 100) )


小高斯發現,其實list comprehension 就已經生成實體的list了,不用額外建立變數,可以直接放在sum裡面做加總計算。

def range_sum(start, end):

return sum( [ i for i in range(start, end+1) ] )

print( range_sum(1, 100) )

輸出結果

5050


小高斯中途休息喝水時,又瞥見桌上的PEP 289的標題就是Generator expressions,還可以使用生成器的方式來動態生成元素,更節省記憶體。

Generator expression

def range_sum(start, end):

return sum( ( i for i in range(start, end+1) ) )

print( range_sum(1, 100) )

輸出結果

5050


小高斯看著輸出畫面,又想到range本身就是一個帶有定義的序列,可以直接放在sum()作加總。

Sum() with range

def range_sum(start, end):

return sum( range(start, end+1) )

print( range_sum(1, 100) )


接著,他又想起好像在書上看過,python支持functional programming,函數式計算,一個function的輸出可以傳給另一個function當作輸入。

相當於用add當作運算子,對1,2,3,...,100 做 map reduce,就可以得到1+2+3+...+100。

Map Reduce

from functools import reduce
from operator import add

def range_sum(start, end):

return reduce(add, (i for i in range(start, end+1) ) )

print( range_sum(1, 100) )

輸出結果

5050


其中,add也可以不要import,用lambda expression 代替

from functools import reduce

def range_sum(start, end):

return reduce(lambda x,y: x+y, (i for i in range(start, end+1) ) )

print( range_sum(1, 100) )

輸出結果

5050

這時候,小高斯還專注在思考的過程中,
忽然聽見熟悉的下課鐘聲聲響起,噹~噹~噹~噹~噹~噹~噹~噹~

小高斯這才心滿意足地將程式碼存檔,關上電腦,收好課本。

準備到體育館去和同學一起參加下一節的體育課。

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.