连分数
连分数的概念和来源
连分数是一种用有理数来逼近一个实数的好方法。比如我们对于无理数\(\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