已知數列求其通項公式

霧小六霧發表於2020-12-23

已知數列求其通項公式

一、引子

1.什麼是通項公式

先來解釋下什麼叫做 ‘已知數列求其通項公式’

給你一個數列
[2,4,6,8,10]
不用算我們就知道這個數列的規律:
非零自然數的偶數數列
y = 2x

再給你這個數列
[11,16,21,26]
稍做計算我們就知道這個數列的規律
y = 5x + 6

但是如果我給你這個數列呢
[2,3,4,5,7,8,65,2,6,-9]
也許我們怎麼計算都算不出來了

說實話這個數列是我隨便打的,但是它也有一個規律,就是這個數列的通項公式:
我們用程式算一下:
y = -157/11340x9+1913/2880x8-205817/15120x7+74767/480x6-117911/108x5+4640659/960x4-609065669/45360x3+16097077/720x2-12594161/630x+7178
不用懷疑,你可以自己算一下(我打賭你不會這麼做),按照這個通項公式去計算,第十個數是-9,第十一個是-12776,第十二個是-111703……它們都符合這個通項公式

看過這篇文章,假如你的老師問你這個數列的下一個數字是什麼
[6,2,8,2,10,18],
你可以毫不猶豫的告訴他:-116
如果你的老師說不對,應該是4,就把這篇文章轉給他,並對他說一句話:

“數列問題
是沒有正確答案的”

(老師罵不罵你我就不知道了)

2.通項公式的作用

言歸正傳,那麼通項公式有什麼用呢?
如果有一個數列[1,2,3,4]
我們通常會認為下一個數是什麼?
5
不過它也有可能是這樣的數列
[1,2,3,4,10,20,30,40,100,200,300,400]
數列是無限延續的,所以看到最後一個也不一定能知道下一個數字是多少。
所以才會說:

“數列問題
是沒有正確答案的”

我們無法發現絕對的數列規律,因為真正的數列模型是不確定的,所以我們就需要一個通項公式來計算這個數列的其中一種一定存在的規律

3.本文中的一些定義

首先,我要明確的告訴你,絕對的通項公式是一定不存在的(因為數列是無限延續的)。
我們的通項公式只能計算相對的規律,也就是計算到有限數列(已知數列)的最後一項。
諸如斐波那契數列、π小數點後的數字的數列這種能用遞迴或語言表述的數列,我們也能計算出通項公式,但是這個數列就不再是原來所表述的數列了,而是這個通項公式所創造的數列.
1.項
項是什麼?
簡單來說,數列的第一個數就是第一項,第二個數是第二項……
2.y
在本文中y就是數列的每一項的數值,
比如說
數列[5,6,7,8]
y1就是5,y2就是6
3.x
在本文中y就是數列的每一項,
比如說
數列[5,6,7,8]
x1就是1,x2就是2

二、程式碼

純程式碼在這篇文章,如果看不懂再回來看,或者直接跟我繼續看下去吧

三、程式碼解釋

總的來說,大體分為以下三大類:
1.得到已知數列
2.計算出通項公式
3.利用通項公式去求出任意項的數應該是什麼

1.得到已知數列

計算
太簡單了,直接寫出程式碼

from fractions import Fraction as fra

數列個數 = int(input('數列個數'))
已知數列 = []
for i in range(數列個數):
    已知數列.append(fra(input('第'+str(i+1)+'個數')))
#詢問已知條件,得到已知數列

這裡只需要注意python的浮點數並不精準,需要把浮點數轉換成分數。
如果你只用程式計算整數數列,就把fra()改成int()就可以了。
不過一定要呼叫fractions模組,後面計算通項公式的時候用的上。

2.計算通項公式

0.三個數怎麼求出數列的通項公式

這裡比較複雜,難思考出程式怎麼去設計,我們先用數學方法去思考一下
(這裡是程式設計的數學方法(通項公式形成的過程))
首先看三個數怎麼求出數列的通項公式
y = ax2 +bx +c
這是三個數的數列的通項公式
現在x1,x2,x3是已知的,分別是1,2,3;也就是說,只要我們有y1,y2,y3的值,就能求出這個數列的通項公式。
先把x1,2x,x3,代入到y=ax^2+bx+c中,
y1=a+b+c
y2=4a+2b+c
y3=9a+3b+c
列出這幾個式子我們就開始消元
y2-y1=3a+b
y3-y2=5a+b
消掉了c
(y3-y2)-(y2-y1)= 2a
消掉了b,
這樣我們就得到了a
a=((y3-y2)-(y2-y1))/ 2
同樣的,利用y2-y1=3a+b這個式子,我們又能得到b
b = y2-y1-3a
利用y1=a+b+c,
c = y1-a-b
這樣,我們就得到了通項公式的所有係數。

代入到程式當中試一試:
(在原程式基礎上)

def 已知三個數求數列():
    係數數列 = []
    係數數列.append(fra(((已知數列[2]-已知數列[1]-(已知數列[1]-已知數列[0]))/2)))
    係數數列.append(fra(已知數列[1]-已知數列[0]-3*係數數列[0]))
    係數數列.append(fra(已知數列[0]-係數數列[0]-係數數列[1]))
    print(係數數列)
    print('通項公式:'+'\ny='+str(係數數列[0])+'x^2+'+str(係數數列[1])+'x+'+str(係數數列[2]))

已知三個數求數列()

執行效果:

數列個數31個數52個數63個數9
[Fraction(1, 1), Fraction(-2, 1), Fraction(6, 1)]
通項公式:
y=1x^2+-2x+6

程式執行成功
(記得現在數列個數我們只能輸入3)
我們來驗證一下程式有沒有出錯,
首先當x=1時,y = 5
1x1x1-2x1+6 = 5
當x = 2時,y = 6
1x2x2-2x2+6 = 6
當x = 3時,y = 9
1x3x3-2x3+6 = 9
全部正確

不過我們看看輸出的通項公式,符號好像有一點小問題——正負號
(這點並不影響程式的正常工作,我們出於便於閱讀通項公式的角度給它修正一下)

1.輸出通項公式

實際上,修改它的正負號,不就是把通項公式便於閱讀的輸出出來嗎

一個通項公式應該是這樣的結構:

y = axn ? axn-1 ? axn-2 …? ax1 ? ax0

其中a是這一項的係數,?代表符號

我們要改的地方:
1)任意一項的a = 0,省略這一項
2)任意一項的a = 1,省略a
3)x的指數 = 1,省略x1 中的指數1
4)x的指數 = 0,省略x0

改正的程式碼如下:

print(係數數列)
print('通項公式:' + '\ny = ' , end='')
b = 1
for i in range(數列個數):
    a = 數列個數 - i - 1
    if 係數數列[i] != 0:
        if 係數數列[i] > 0 and b == 0:
            print('+', end='')
        if 係數數列[i] != 1:
            print(str(係數數列[i]), end='')
        if a > 1:
            print('x^'+str(a), end='')
        elif a == 1:
            print('x', end='')
        b = 0

執行效果:

數列個數31個數32個數63個數9
[Fraction(0, 1), Fraction(3, 1), Fraction(0, 1)]
通項公式:
y = 3x

程式執行成功

0.接下來的程式設計思路

接下來的程式設計思路要去參考三個數怎麼求出通項公式
首先思考一下三個數求通項公式的步驟:

1) 求出y3-y2和y2-y1
2) 求出前面兩個差的差
3) 將最後的差除以一個常數得出a的係數
4) 再利用做過差的式子,將a代入其中,求出b,c的值

所以任意數求通項公式的步驟應該是:

1)求出 yn - y(n-1),
y(n-1)- y(n-2)
……
2)求出(yn - y(n-1)) - (y(n-1) - y(n-2)) ,
(y(n-1) - y(n-2)) - (y(n-2) - y(n-3))
……
3)將最後的差除以一個常數,得出a的係數
4)利用之前作差後得到的式子,將a代入其中,求出b,c,d……的值

以上就是我們要用程式做的數學計算,將它們都做成程式碼,我們的程式就OK了
那麼做這個程式應該分為哪幾步呢?

做程式的步驟:
1)自定義一個作差函式

稍後我們再解釋,不過這個函式幫我們完成了上述數學方法中的(1)和(2)

2)求出常數數列
稍後我們解釋說明叫做常數數列,它幫我們完成了上述數學方法中的(3)
3)求出係數數列
4)利用(2)和(3)求出通項公式

2.自定義做差函式

我們輸入一個列表,它返回我們一個作差後的字典
這個字典的格式應該是這樣的:
假如我們輸入的列表是【1,2,6,5,8,4,32】
它應該返回的字典:

 {0: [1, 2, 6, 5, 8, 4, 32], 
 1: [1, 4, -1, 3, -4, 28],
 2: [3, -5, 4, -7, 32],
 3: [-8, 9, -11, 39],
 4: [17, -20, 50], 
 5: [-37, 70], 
6: [107]}

其中鍵0是原列表,每一個數字鍵都是作差幾次後的結果, 最後一個數字鍵是最終的值,就是我們用來求a的值
程式碼如下:

def 作差(a):
    b = {0: a}
    for i in range(len(a)-1):
        b[i+1] = [b[i][n+1] - b[i][n] for n in range(len(a)-i-1)]
    return b
#求差值用的函式,接收列表,返回字典

其中,引數a是函式接收的要去作差的列表,b是函式用來作差的中間值,很簡單,簡單看一下就好了

執行效果:

{0: [5, 6, 92, -56, 22],
 1: [1, 86, -148, 78],
 2: [85, -234, 226],
 3: [-319, 460], 
 4: [779]}

程式碼執行成功

3.得到常數數列

常數數列就是之前算三個數求數列通項公式計算通項公式所用的每一個數字
例如:
a=((y3-y2)-(y2-y1))/ 2
b = y2-y1-3a
c = y1-a-b
2、3、1、1就是這個通項公式用的常數

那麼這個數列怎麼去求呢?

我們這次以五個數求數列通項公式為例

y = ax4 + bx3 + cx2 + dx + e

a +b + c + d + e = y1
16a + 8b +4c +2d +e = y2
81a +27b +9c +3d +e = y3
256a +64b +16c +4d +e = y4
625a +125b +25c +5d +e = y5

1,16,81,256,625就是a的常數數列
1,8,27,64,125就是b的常數數列
1,4,9,16,25就是c的常數數列
1,2,3,4,5就是d的常數數列
1,1,1,1,1就是e的常數數列

我相信你已經看出來常數數列是怎麼求的了

程式碼如下:

常數數列 = {}
for i in range(數列個數):
    常數數列[數列個數-i] = [(n+1)**i for n in range(數列個數)]
#得到常數數列
0.關於作差和‘!’

在寫這個程式的時候我偶然發現:
12 , 22 , 32 把它作差最後的得數就是2!
13 , 23 ,33 ,43把它作差後的得數就是3!
……
我現在還不知道是什麼原理,但初步判斷和帕斯卡三角形有關係,
如果大家有誰算出了是什麼原理,請在評論區說出來或者直接私信我,謝謝了

4.得到係數數列

那麼得到常數數列後我們可以幹嘛呢?
沒錯,那就是可以得到係數數列。怎麼得到呢?
還以五個數求通項公式為例

a +b + c + d + e = y1
16a + 8b +4c +2d +e = y2
81a +27b +9c +3d +e = y3
256a +64b +16c +4d +e = y4
625a +125b +25c +5d +e = y5

15a+7b +3c +d = y2 - y1
65a + 19b +5c +d = y3 -y2
175a + 37b + 7c + d = y4 -y3
369a + 61b +9c +d = y5 -y4
消掉了e

50a + 12b + 2c = (y3-y2) - (y2-y1)
110a +18b +2c = (y4-y3) - (y3-y2)
194a + 24b + 2c = (y5-y4) - (y4-y3)
消掉了d

60a + 6b = ((y4-y3) - (y3-y2))-((y4-y3) - (y3-y2))
84a + 6b = ((y5-y4) - (y4-y3) )-( (y4-y3) - (y3-y2))
消掉了c

24a =(((y5-y4) - (y4-y3) )-( (y4-y3) - (y3-y2)))-(((y4-y3) - (y3-y2))-((y4-y3) - (y3-y2)))
消掉了b

a = ((((y5-y4) - (y4-y3) )-( (y4-y3) - (y3-y2)))-(((y4-y3) - (y3-y2))-((y4-y3) - (y3-y2)))) / 24
b = (((y4-y3) - (y3-y2))-((y4-y3) - (y3-y2)) - 60a) / 6
c = ((y3-y2) - (y2-y1) -50a -12b) / 2
d = (y2 - y1) - 15a -7b -3c
e = y1 - a -b -c -d

不斷的用消元法,這樣我們就得到了所有的係數

我們看上面的a,b,c,d,e,全部都是等於 (x-y) / z的形式

其中x都是已知數列作差的結果
z都是該字母對應的常數數列的作差的第對應項
(這時候就能看出作差函式的厲害之處了吧)

那麼y呢,這個不是很好看出來,我們一個一個看

第一個y = 0
第二個y = - 60a
第三個y = -50a -12b
第四個y = -15a -7b -3c
第五個y = -a -b -c -d

發現了嗎

去掉第一個求a的y我們不看(a直接用x/z就可以求出來了)
第二個y的60是作差(常數數列【a】)的倒數第二項的第一項
第三個y的50是作差(常數數列【a】)的倒數第三項的第一項
第三個y的12是作差(常數數列【b】)的倒數第三項的第一項
……
這樣我們就得到了係數數列

程式碼如下:

已知數列作差 = 作差(已知數列)
係數數列 = []
for i in range(1, 數列個數+1):
    x = 已知數列作差[數列個數 - i][0]
    z = 作差(常數數列[i])[數列個數 - i][0]
    if i != 1:
        y = 0
        for n in range(1, i):
            y += 作差(常數數列[n])[數列個數-i][0]*係數數列[n-1]
        係數數列.append((x-y)/z)
    else:
        係數數列.append(x / z)
#得到通項公式

3.用通項公式去計算第n項

在做這步之前,我們先說一點,在真正的程式碼中輸出係數數列應該在得到係數數列之後,因為我們先做三個數求數列通項公式的緣故,所以先把輸出係數數列做出來了

這步也比較簡單啊,畢竟不涉及到數學問題的思考,我就直接上程式碼了

程式碼如下:

c = 1
print('\n')
while c:
    a = int(input('數列第幾個數'))
    if a == 0:
        c = 0
        print('程式停止執行')
        pass
    else:
        b = 0
        for i in range(1, 數列個數+1):
            b += 係數數列[i-1]*a**(數列個數-i)
        print(b)
# 詢問數列的位置,並回答在數列該位置上的數

其中,c是用來控制程式停止執行的,如果使用者輸入0,程式就會停止執行

執行效果:

數列個數51個數22個數63個數94個數55個數3
[Fraction(5, 8), Fraction(-29, 4), Fraction(219, 8), Fraction(-147, 4), Fraction(18, 1)]
通項公式:
y = 5/8x^4-29/4x^3+219/8x^2-147/4x+18

數列第幾個數6
27
數列第幾個數9
720
數列第幾個數0
程式停止執行

四、小結

文章到這裡就結束了,這是我第一次發文章,也不知道能不能有人看到,這篇文章除了y=ax3 + bx2 + cx + d這個公式是我初中數學老師告訴我的,其餘都是從零到一自己研究出來的,期間程式碼和這篇文章改了好久,因為我不確定我寫出來的程式碼大家能不能看得明白,畢竟有些地方存在不規範。

如果大家發現問題、或者有疑問,或者有有關數學方面或者程式的其他有趣的問題,歡迎大家在評論區指出,或者私信我,如果我有時間的話都會回覆的。

文章程式碼

相關文章