我正在尝试通过计算公式来计算e常数(又称为Euler数)
为了一口气计算出阶乘和除法,我这样写:
my @e = 1, { state $a=1; 1 / ($_ * $a++) } ... *;
say reduce * + * , @e[^10];
但这没有解决。如何正确做?
$_
变量而无法构造出来,从而试图构造阶乘。这显然是多余的。在下面的正确解决方案中,$_
它被丢弃,并且效果很好。
我正在尝试通过计算公式来计算e常数(又称为Euler数)
为了一口气计算出阶乘和除法,我这样写:
my @e = 1, { state $a=1; 1 / ($_ * $a++) } ... *;
say reduce * + * , @e[^10];
但这没有解决。如何正确做?
$_
变量而无法构造出来,从而试图构造阶乘。这显然是多余的。在下面的正确解决方案中,$_
它被丢弃,并且效果很好。
Answers:
我将在分析代码部分中分析您的代码。在此之前,我介绍了一些有趣的奖金材料部分。
say e; # 2.718281828459045
单击上面的链接,查看Damian Conway e
在Raku中有关计算的非凡文章。
这篇文章很有趣(毕竟是达米安)。这是关于计算的非常容易理解的讨论e
。这是对Laku Wall所倡导的TIMTOWTDI哲学的碳酸氢盐转世的致敬。3
作为开胃菜,以下为文章中途的一句话:
鉴于这些有效的方法都以相同的方式工作(通过对一系列无限项的求和(它们的初始子集)),如果我们有一个功能可以做的更好。如果函数能够准确地自己算出该序列的初始子集实际多少以产生准确的答案,那肯定会更好,而不是要求我们手动梳理函数的结果。多次试验发现了这一点。
而且,就像在Raku中一样,构建我们所需的东西非常容易:
sub Σ (Unary $block --> Numeric) {
(0..∞).map($block).produce(&[+]).&converge
}
这是生成系列的第一行:
my @e = 1, { state $a=1; 1 / ($_ * $a++) } ... *;
闭包({ code goes here }
)计算一项。闭包具有一个隐式或显式签名,该签名确定它将接受多少个参数。在这种情况下,没有显式签名。使用$_
(“ topic”变量)会导致隐式签名,该签名需要绑定到的一个参数$_
。
序列运算符(...
)反复调用其左侧的闭包,将前一项作为闭包的参数传递,以延迟构建一系列术语,直到其右端的端点(在本例中*
为Inf
aka infinity的简写)。
第一次调用闭包的主题是1
。因此,闭包计算并返回1 / (1 * 1)
,得出序列中的前两项为1, 1/1
。
第二个调用中的主题是上一个1/1
(即1
再次)的值。因此,闭包计算并返回1 / (1 * 2)
,将序列扩展到1, 1/1, 1/2
。一切看起来不错。
下一个闭包计算1 / (1/2 * 3)
为0.666667
。这个词应该是1 / (1 * 2 * 3)
。哎呀
您的代码应该符合以下公式:
在此公式中,每个术语都是根据其在系列中的位置计算的。系列中的第k个项(第一个中k = 0 1
)只是阶乘k的倒数。
(因此,它与前一项的值无关。因此$_
,接收前一项值的,不应在闭包中使用。)
让我们创建一个阶乘后缀运算符:
sub postfix:<!> (\k) { [×] 1 .. k }
(×
是一个中缀乘法运算符,是通常的ASCII infix 的漂亮Unicode别名*
。)
这是以下简称:
sub postfix:<!> (\k) { 1 × 2 × 3 × .... × k }
(我在花括号内使用了伪元语法符号来表示根据需要添加或减去任意多个项的想法。
更一般而言,将infix运算符op
放在表达式的开头放在方括号中,会形成一个等效于的复合前缀运算符reduce with => &[op],
。有关更多信息,请参见还原元运算符。
现在我们可以重写闭包以使用新的阶乘后缀运算符:
my @e = 1, { state $a=1; 1 / $a++! } ... *;
答对了。这产生了正确的系列。
...直到没有,因为另一个原因。下一个问题是数值精度。但是,让我们在下一部分中进行处理。
也许将三行压缩为一:
say [+] .[^10] given 1, { 1 / [×] 1 .. ++$ } ... Inf
.[^10]
适用于由设置的主题given
。(^10
是的简写0..9
,因此上面的代码计算序列中前十个项的和。)
我$a
已从下一学期的闭包计算中删除了。孤独$
与(state $)
匿名状态标量相同。我将其设置为pre-increment而不是post-increment,以实现与初始化$a
为相同的效果1
。
您现在在下面的评论中指出了最后一个(大!)问题。
如果两个操作数都不是Num
(浮点数,因此是近似值),则/
运算符通常返回100%的精度Rat
(有限精度的有理数)。但是,如果结果的分母超过64位,则该结果将转换为Num
-以牺牲性能为代价,这是我们不想做的折衷。我们需要考虑到这一点。
要指定无限制的精度以及100%的精度,只需强制操作使用FatRat
s。为了正确地做到这一点,只需(至少)使一个操作数为a FatRat
(而其他都不为Num
):
say [+] .[^500] given 1, { 1.FatRat / [×] 1 .. ++$ } ... Inf
我已将此值验证为500个十进制数字。我希望它能保持准确,直到程序由于超出Raku语言或Rakudo编译器的某些限制而崩溃为止。(有关此问题的讨论,请参见我对无法将65536位宽的bigint开箱到本机整数的答复。)
1乐具有内置的,包括一些重要的数学常数e
,i
和pi
(和它的别名π
)。因此,人们可以像在数学书中那样,在Raku中写出Euler的身份。归功于RosettaCode的Raku条目以证明Euler的身份:
# There's an invisible character between <> and iπ character pairs!
sub infix:<> (\left, \right) is tighter(&infix:<**>) { left * right };
# Raku doesn't have built in symbolic math so use approximate equal
say e**iπ + 1 ≅ 0; # True
2 Damian的文章是必读的。但这只是Google'raku“ euler's number”'的100多个匹配项中的几种令人钦佩的处理方式之一。
3请参阅TIMTOWTDI与TSBO-APOO-OWTDI,了解由python爱好者编写的TIMTOWTDI的更为平衡的视图之一。但是,将TIMTOWTDI放得太远也有弊端。为了反映后者的“危险”,Perl社区创造了幽默长,难以理解且被低估的TIMTOWTDIBSCINABTE-有多种方法可以实现,但有时一致性也不是坏事,发音为“ Tim Toady Bicarbonate”。奇怪的是,拉里将碳酸氢盐应用于Raku的设计中,而Damian将其应用于Raku的计算e
中。
$
是的简写state $
,非常方便。
e
第三个解决方案的位数(标题为我的方式基于您的方式)?我尝试在1中的旁边添加FatRat(500):... given 1.FatRat(500), ...
使数字精确到500位,但是没有用。
FatRat
在上一节中已经解决了您非常重要的问题。尽管唯一的主要变化是FatRat
内容,但我也磨练了整个答案。(顺便说一句,我意识到我的回答实际上与您最初的问题有关;我相信您不介意我写所有多余的内容以娱乐自己,并且可能对以后的读者很有趣。)
.FatRat
扩展名必须放在代码生成器内部。现在,我尝试用FatRat
这种方式添加它,并将e计算为1000位数以上的精度。添加的额外绒毛是麦芽汁。例如,我不知道会say
截断长数组/序列。这样的信息点是很好知道的。
.FatRat
扩展名必须放在代码生成器内部。” 是。更一般而言,如果已经对涉及除法的表达式进行了求值,那么现在要消除Rat
精度溢出导致的损害为时已晚。如果有,它将评估为Num
(浮点数),进而污染涉及该点的任何进一步计算,也使它们也 变为Num
。确保事物停留的唯一方法FatRat
是启动它们,FatRat
并避免出现任何错误Num
。Int
s和Rat
s可以,只要至少有一个FatRat
让Raku知道要坚持FatRat
s。
中有分数$_
。因此,您需要1 / (1/$_ * $a++)
还是宁愿$_ /$a++
。
通过Raku,您可以逐步进行此计算
1.FatRat,1,2,3 ... * #1 1 2 3 4 5 6 7 8 9 ...
andthen .produce: &[*] #1 1 2 6 24 120 720 5040 40320 362880
andthen .map: 1/* #1 1 1/2 1/6 1/24 1/120 1/720 1/5040 1/40320 1/362880 ...
andthen .produce: &[+] #1 2 2.5 2.666667 2.708333 2.716667 2.718056 2.718254 2.718279 2.718282 ...
andthen .[50].say #2.71828182845904523536028747135266249775724709369995957496696762772
andthen
。