Mathematica 显示连分数的4种方法

本文详细介绍了Mathematica中显示连分数的四种方法:实数展开、连分数值计算、HoldForm、Inactivate和Defer,并展示了如何使用这些技巧获取和显示连分数的整数序列,以及它们各自的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mathematica 显示连分数的4种方法

实数的连分数展开

连分数可用来方便地得到对无理数的优异的有理数逼近。例如 π \pi π的连分数表示形式为

π = 3 + 1 7 + 1 15 + 1 1 + 1 292 + 1 1 + 1 1 + 1 1 + 1 2 + 1 1 + … \pi=3+\frac{1}{7+\frac{1}{15+\frac{1}{1+\frac{1}{292+\frac{1}{1+\frac{1}{1+\frac{1}{1+\frac{1}{2+\frac{1}{1+\dots}}}}}}}}} π=3+7+15+1+292+1+1+1+2+1+111111111

可记为 [ 3 ; 7 , 15 , 1 , 292 , 1 , 1 , 1 , 2 , 1 , ⋯   ] [3; 7, 15, 1, 292, 1, 1, 1, 2, 1,\cdots] [3;7,15,1,292,1,1,1,2,1,]

截取其前2项及前3项分别为 3 + 1 7 = 22 7 \displaystyle 3+\frac{1}{7}=\frac{22}{7} 3+71=722 3 + 1 7 + 1 15 = 333 106 3+\cfrac{1}{7+\dfrac{1}{15}}=\cfrac{333}{106} 3+7+1511=106333,正是祖冲之得到的约律 22 7 \dfrac{22}{7} 722和密率 333 106 \dfrac{333}{106} 106333

那么,怎样得到连分数中的整数序列呢?

可以通过直接展开法1

ExpandZJ[alpha_,r_Integer:10]:=Module[
	{x1,A1=Rationalize[alpha,0],a1,l={},k},
	Do[
		a1=Floor[A1];x1=A1-a1;
		AppendTo[l,a1];
		If[x1==0,Break[]];A1=1/x1,
		{k,1,r}
	];
	l
]

注意,用计算机计算时,alpha需被转化为有理数进行运算,因为浮点数的精度问题导致迭代几次后数值不准。

也可以通过辗转相除法1

ExpandZZ[alpha_,r_Integer:10]:=Module[
	{rkm=Rationalize[alpha,0],rk=1,rkp,ak,l={}},
	Do[
		If[rk==0,Break[]];
		{ak,rkp}=QuotientRemainder[rkm,rk];
		{rkm,rk}={rk,rkp};
		AppendTo[l,ak],
		{k,1,r}
	];
	l
]

不过作为世界三大数学软件之一,Mathematica内置了连分数展开的函数,即用ContinuedFraction[x,n]生成 x 的连分数表示中前 n 项的列表。这三个函数运行如下:

在这里插入图片描述

计算连分数的值

有限连分数的形式表明它的计算方法是由下向上的,即对于 a + 1 b + 1 c + 1 d a+\frac{1}{b+\frac{1}{c+\frac{1}{d}}} a+b+c+d111,我们先计算 c + 1 d c+\frac{1}{d} c+d1,再计算 b + 1 ( c + 1 d ) b+\frac{1}{(c+\frac{1}{d})} b+(c+d1)1,最后计算 a + 1 ( b + 1 c + 1 d ) a+\frac{1}{(b+\frac{1}{c+\frac{1}{d}})} a+(b+c+d11)1。这可以看做一种“含参数”函数的迭代过程,即 f a ( f b ( f c ( d ) ) ) ) f_a(f_b(f_c(d)))) fa(fb(fc(d)))),其中 f i ( x ) = i + 1 x f_i(x)=i+\frac{1}{x} fi(x)=i+x1。或者看做 f ( f ( f ( d , c ) , b ) , a ) f(f(f(d,c),b),a) f(f(f(d,c),b),a),其中 f ( x , i ) = i + 1 x f(x,i)=i+\frac{1}{x} f(x,i)=i+x1。对于一般的迭代,mma中的Nest函数可以实现,而对于这种“含参数”函数的迭代,mma中的FoldList函数恰好可以实现。

在这里插入图片描述

查阅mma的文档,我们可以得知:Fold[f, {d, c, b, a}]==f[f[f[d, c], b], a]

于是我们可以这样计算连分数:list = ContinuedFraction[Pi, 10]; Fold[#2 + 1/#1 &, Reverse@list]
其中#2 + 1/#1 &表示一个纯函数,其意义相当于定义了f[x_,y_]:=y+1/x后的fReverse表示反转列表,因为如前所述,我们的计算是由下向上的。
实际运行如下:
在这里插入图片描述

显示连分数

在得到连分数中的整数序列后,下面来看看怎么显示连分数。
我们对整数的访问过程与上面的计算方法一样,不过要避免数字的计算。

1.String&Orderless

如果a=“1”,b=“1”,那么a+b的值输入mma后会得到"1+1",但显示的效果不带引号,就好像它忘记了计算数字1+1。
我们可以设想,如果把每个整数加上引号变成字符串,那么分数就不会化简了2。实际操作一下:
Fold[(#2 + 1/#1) &, ToString /@ Reverse@ContinuedFraction[Pi, 10]]
在这里插入图片描述
发现连分数的效果有了,但是排列的并不美观。猜测与表达式的排序有关(它自动忽略了加法的顺序,当然加法默认没有顺序)。不过可以清除Plus的无序属性来取消它的自行排列。当然清除后建议立刻恢复,否则输入a + b + a的结果将原封不动地返回,而不是2 a + b。如果要从显示的连分数恢复成化简后的分数,需要将所有的字符串替换成它的表达式结果。这是代码实现及效果:

ClearAttributes[Plus, Orderless]
Fold[(#2 + 1/#1) &, ToString /@ Reverse@ContinuedFraction[Pi, 10]]
% /. x_String :> ToExpression[x]
SetAttributes[Plus, Orderless]

在这里插入图片描述

2.HoldForm

HoldForm保持表达式不计算的形式,恢复计算则需要ReleaseHold //@expr。

Fold[#2 + 1/HoldForm[#] &, Reverse@ContinuedFraction[Pi, 10]]
ReleaseHold //@ %

在这里插入图片描述

3.Inactivate

Inactivate使Plus失效,恢复只需要Activate作用。

Fold[Inactivate[#2 + 1/#1, Plus] &, Reverse@ContinuedFraction[Pi, 10]]
Activate[%]

在这里插入图片描述

4.Defer

Defer(推迟计算),只有当表达式显式地输入时才计算,而恢复则需要复制结果后直接输入。

Fold[#2 + 1/Defer[#1] &, Reverse@ContinuedFraction[Pi, 10]]

在这里插入图片描述

写在最后

以上四种方法中,个人比较喜欢HoldForm实现的。因为听群里大神说mma中字符串效率比Inactive低很多。而Inactive实现的结果中加号的颜色变暗了,且最后一个分数中分母是1时,没显示成1/1。Defer的话,还要再手动复制输入一遍,程序处理中显得不方便。实际上,HoldForm(还有Inactive)加的位置也是多次尝试出来的,读者可以试试Fold[#2 + HoldForm[1/#1] &, Reverse@ContinuedFraction[Pi, 10]],其显示末尾的“1×1/1”,并不好看,也不知原因(欢迎补充)。

显示连分数原本是数学实验作业中遇到的问题,本文中四种方法的(貌似)中间两种是在mma群里询问大佬们才得知的。当年迎难而上,精益求精,可今非昔比,岁月蹉跎,感慨万千。

最后,送给大家给大家准备一个连分数:
5+1/(4+1/(1+1/(29+1/(1+1/(1+1/(1+1/(3+1/(1+1/(2+1/(1+1/(2+1/(1+1/(1+1/9))))))))))))),它是由某个小数填入代码
Fold[#2 ~~ "+1/(" ~~ #1 ~~ ")" &, ToString /@ Reverse@ContinuedFraction[Rationalize[1.42857, 0]]]中1.42857的位置得到的,至于该小数是多少,大家一算便知[滑稽]。


  1. 李尚志《数学实验》 ↩︎ ↩︎

  2. Mathematica基础——处理连分数问题-百度经验 https://jingyan.baidu.com/article/7c6fb42821117b80642c90f3.html ↩︎

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值