連分數的概念和來源
連分數是一種用有理數來逼近一個實數的好方法。比如我們對於無理數\(\pi\),可以用分數\(\frac{314}{100}=\frac{157}{50}=3.14\)來近似的表示,但是分數\(\frac{31415}{10000}=\frac{6283}{2000}=3.1415\)是對於\(\pi\)的一個更好的逼近,而連分數方法就可以不斷的得到越來越好的逼近。
連分數的思想
設需要逼近的實數為x,不斷的找一個近似的有理數y(小於等於x),然后再找到一個小於等於x-y的有理數,重復直到達到精度要求或者最后尋找的近似數與被近似的數相等時,將這些數相加即可,因為后面需要近似的數越來越小,所以可以很容易看出精度在不斷的提高。
連分數的表示與一些性質
舉例:
在連分數中,從開始一直到第k個變元(\(a_k\))構成的連分數,就是這個連分數的第k漸進分數,記作\(\frac{p_k}{q_k}\)。
最后一個漸進分數,也就是這個被逼近的數本身,第一個漸進分數就是\(a_0\)
漸進分數的分子\(p_k\)和\(q_k\)具有相同的遞推關系:
而為了滿足形式,記:
連分數的計算方法
如果只按照上面這種敘述,其實很難理解到底應該怎么算,其實連分數的計算很簡單,主要也就是用到了求最大公約數時用到的輾轉相除法/歐幾里得算法,只不過gcd是算式\(a=kb+c\)中最后一個不為0的c就是最大公約數,而計算連分數需要用到每一個k(包括最后一個)。舉個例子:
其中\(5=\textbf{1}\times 4+1\)中最后這個加的1就是12345和11111的最大公約數(最后一個非0的余數),而所有加粗的數字就是計算連分數所需要的變元\(a_k\)。
有了變元,就可以利用上述的遞推公式找到每一個漸進分數的分子和分母了。
連分數的代碼實現
在sagemath中,求變元的公式是:continued_fraction(a/b),這個是一個‘sage.rings.continued_fraction.ContinuedFraction_periodic’類,可以遍歷,如果需要變成列表可以用強制類型轉換:list(contFrac(a/b)),然后把分子分母求出來就是用這個類的方法convergents(),返回一個列表。
例如:
>>> a = continued_fraction(12345/11111)
>>> b = a.convergents()
>>> print(a)
[1, 9, 246, 1, 4]
>>> type(a)
<class 'sage.rings.continued_fraction.ContinuedFraction_periodic'>
>>> print(b)
[1, 10/9, 2461/2215, 2471/2224, 12345/11111]
>>> type(b)
<class 'list'>
也可以自己寫:
#計算a/b的連分數的變元
def contFrac(a, b):
l = []
if b > a:
a, b = b, a
while b:
l.append(a//b)
a, b = b, a%b
return l
def fun(cc):
p_be, p_af = 0, 1
q_be, q_af = 1, 0
for i in cc:
p_be, p_af = p_af, i * p_af + p_be
q_be, q_af = q_af, i * q_af + q_be
return p_af, q_af