我们给出了计算a中π的位数的算法上一次练习。今天,我们来看两种用于计算e(电子)。
我们从一个算法由于斯坦利·拉比诺维茨和斯坦·瓦贡:
算法电子插口:计算第一个n个十进制数字e(电子)以下为:
1初始化:让第一个数字为2并初始化数组A类长度的n个+1到(1,1,1…,1)。
2.重复n个−1倍:
乘以10:将每个条目相乘A类10倍。
取分数部分:从右侧开始,减少我第个条目A类模我+1,将商保留一位。
输出下一个数字:最终商是e(电子)。
我们给出了前十位数字的计算示例e(电子)上下一页,其中我们计算e(电子)作为2 7 1 8 2 8 1 8 2 6。正如你所看到的,这个算法的最后一个数字可能是错误的(应该是8,而不是6);事实上,正如论文所指出的,在某些情况下,最后几个数字可能是错误的。该算法还受到一个事实的影响,即它是有界的,这意味着必须提前指定数字的数量,并且它需要的空间与n个2。
一个不同的算法来自杰里米·吉本斯(Jeremy Gibbons),是无界的,只需要恒定的空间;吉本斯给出了π的序列,但汤姆·莫特尔适应它是为了e(电子)当我无法根据莫特尔的描述计算出算法时,我向《编程实践》(Programming Praxis)的定期撰稿人雷姆科·尼梅耶(Remco Niemeijer)求助,他用这段漂亮的哈斯克尔代码来回应,该代码可以计算π和e(电子)以下为:
流::积分a=>(a,a)->(a,b)->[(a,a,a)]->[a]
流(lo,hi)z~(x:xs)=如果lbound==大约zhi
然后是lbbound:stream(lo,hi)(mul(10,-10*lbbound,1)z)(x:xs)
else流(lo,hi)(mul z x)xs
其中lbound=近似z-lo
近似(a,b,c)n=div(a*n+b)c
mul(a,b,c)(d,e,f)=(a*d,a*e+b*f,c*f)
stream数字::(Num a,Integral a,Enum a)=>(a->(a,a,a))->(a,a)->[a]
流数字f范围=流范围(1,0,1)[(n,a*d,d)|(n,d,a)<-map f[1..]]
stream_pi,stream_e::[整数]
stream_pi=流数字(\k->(k,2*k+1,2))(3,4)
stream_e=流数字(\k->(1,k,1))(1,2)
主::IO()
main=打印$take 30 stream_pi
打印$take 30 stream_e
尼梅耶解释说,他对吉本斯论文中的算法进行了如下修改:
–单元
是仅用于一个位置的常量。删除定义并直接使用该值。
–comp公司
是基本的2×2矩阵乘法。重命名为穆尔
使目的更明确。
–外部
正如论文中所定义的那样,它不是为我编译的:它应该是来自整数(q*x)
而不是来自整数q*x
但还有更多收获:唯一的地方外部
使用的前面是地板
,所以基本上我们有地板(a/b)
,等于分区a b
。因为它是用来近似实际值的,所以我给它命名大约
。
–该代码使用2×2矩阵表示为4元组。但是,左下角元素始终为0。删除所有位置的此元素,保留3元组并使穆尔
和大约
更简单。
–对于π和e(电子),的下一个
和安全的
传递给的函数流动
除了使用的边界外,都是相同的,所以传入边界并将函数集成到流动
。
–年在中使用流动
是下限。相应地重命名。
–欺骗
传递到流总是comp公司
(或者就我而言穆尔
). 删除参数并使用穆尔
直接。
–触头
对于π和e(电子),因此删除参数并内联函数。
–论文中π的定义流动
带有一些起始参数。自e(电子)将执行相同的操作,生成函数stream数字
把这个抽象出来。
–自流动
现在需要的参数少得多,再也没有理由将它们全部命名。
–根据船体位置,π函数中的每项为2+k个/(2k个+ 1)x个。对于e(电子),每项为1+(1/k个)x个(或者更确切地说,它定义了e(电子)−1从开始k个=2,但如果你从k个=1你加上术语1+1/1x个,它为您提供1+1/1*(e(电子)-1) ,当然是e(电子)). 所以两者都是这样的一+ (n个/d日)x个。中使用的矩阵lfts公司
是(n个,一*d日, 0,d日). 我不喜欢自己做乘法,所以我做了流数字
取一个产生n个,d日和一使给定的术语更接近数学定义。此函数用于生成实际矩阵。
–添加流_e
和流_pi
功能。
您的任务是为编写两个插口函数e(电子)如上所述。完成后,欢迎您阅读或运行建议的解决方案,或在下面的评论中发布自己的解决方案或讨论练习。
页:1 2 三