如何让这个raku Muller重复代码一行运作?

7
在回复我最近的博客文章时,Markus H. 提供了一种非常简洁的代码替代方案,即:
dd $_ for (4, 4.25, 108 – (815 – 1500 / * ) / * … *)[^30].kv

很遗憾,我无法让这个"开箱即用"地工作并出现了以下错误:
Confused
at /Users/stephenroe/Dropbox/RakuStuff/mullerrec/./mullerrec3.raku:27
------> dd $_ for (4, 4.25, 108⏏ – (815 – 1500 / * ) / * … *)[^30].kv
    expecting any of:
        infix
        infix stopper
        statement end
        statement modifier
        statement modifier loop

我该如何解决这个问题?

这是我可以运行的代码(是的,我的风格有点不同,但没关系):

sub f(\y,\z) { 
    108 - ( (815 - 1500/z ) / y ) 
}
dd $_ for (4, 4.25, -> \z,\y {f(y,z)}  … ∞)[^30].kv;

作为后续,我认为我需要交换f的参数,但Markus还没有这样做,谁是正确的?我很想知道这是否是一个陷阱,那么问题是“如何通过消耗的星号来反转顺序?”

或者可能像这样:

dd $_ for (4, 4.25, f(^z,^y) … ∞)[^30].kv;   #not legal
1个回答

7

TL;DR 在非Unicode字符集时代,剪切/粘贴是非常困难的,而且越来越糟糕 - 但至少通常会出现乱码,使问题显而易见。在Unicode时代,情况就不同了。你需要执行s/–/-/操作。

进行这个更改,同时进行一些其他更改以切换到希望更具洞察力的显示,并切换到FatRat计算,以便结果100%准确,并具有无限精度

say sprintf "%-2s: %-24s %s / %s", .key, .value, |.value.nude

for (4.FatRat, 4.25, 108 - (815 - 1500 / * ) / * … *)[^30].pairs

0 : 4                        4 / 1
1 : 4.25                     17 / 4
2 : 4.470588                 76 / 17
3 : 4.644737                 353 / 76
4 : 4.770538                 1684 / 353
5 : 4.855701                 8177 / 1684
6 : 4.910847                 40156 / 8177
7 : 4.945537                 198593 / 40156
8 : 4.96696258               986404 / 198593
9 : 4.9800457                4912337 / 986404
10: 4.987979448              24502636 / 4912337
11: 4.9927702881             122336033 / 24502636
12: 4.99565589151            611148724 / 122336033
13: 4.99739126838            3054149297 / 611148724
14: 4.998433943945           15265963516 / 3054149297
15: 4.9990600719709          76315468673 / 15265963516
16: 4.9994359371468          381534296644 / 76315468673
17: 4.99966152410377         1907542343057 / 381534296644
18: 4.999796900713418        9537324294796 / 1907542343057
19: 4.999878135477931        47685459212513 / 9537324294796
20: 4.9999268795045999       238423809278164 / 47685459212513
21: 4.99995612706115774      1192108586037617 / 238423809278164
22: 4.999973676005712445     5960511549128476 / 1192108586037617
23: 4.999984205520272708     29802463602463553 / 5960511549128476
24: 4.9999905232822276594    149012035582781284 / 29802463602463553
25: 4.99999431395855959365   745059330625296977 / 149012035582781284
26: 4.99999658837125602371   3725294111260656556 / 745059330625296977
27: 4.999997953021356907988  18626462930705797793 / 3725294111260656556
28: 4.9999987718123113299994 93132291776736534004 / 18626462930705797793
29: 4.9999992630872057845553 465661390253305305137 / 93132291776736534004

Muller's Recurrence是一种近似方法。但给定迭代的准确度/精度取决于之前迭代的准确度/精度。这些又会受到所使用的数字类型和操作的准确度/精度的影响:
- 使用浮点数/操作,在第12次左右迭代后会产生无用的结果。 - 使用定点数/操作,只要数字保持在其精度范围内就会产生准确的结果,然后很快就会产生无用的结果。 - 在@Holli的代码变体中,我使用了Raku的FatRat数字类型和操作。这可以保持100%的准确性和无限精度。即使是廉价的硬件也可以在不到一秒的时间内轻松地进行大约1,000次迭代,并且准确率为100%。
Muller's Recurrence公式在数学上仅涉及有理数和运算(“有理”包括整数)。 Raku中的数字运算方便地遵循“感染”的规则,即:
  • 每次迭代中至少有一个数字是 FatRat

  • 没有任何数字是 Num(浮点数);

  • 没有任何操作引入了 Num(浮点数);

那么,只要在 Raku 中使用 Muller's Recurrence 公式,并将其中一个数字强制转换为 FatRat,每次迭代都会产生另一个精度为 100% 的 FatRat


2
亲爱的Raiph - 非常感谢你的帮助!(尽管我无法复制和粘贴Unicode,这有点令人尴尬...@markus关于非可逆性是正确的...作为未来的参考,可以反转任何星号吗?) - librasteve
2
@p6steve 不行,你不能反转星号。你必须使用大括号。例如 4, 4.25.FatRat, { 108 - (815 - 1500 / $^foo ) / $^bar } … * 将会反转参数/参数列表,因为 bar 在字典序中排在 foo 之前。 - raiph
1
raiph,我使用dd,因为它将Rats显示为分子/分母,从而显示我们开始失去精度的位置。 - Holli
1
@Holli 根据您的评论,我已经编辑了我的回答。希望这些修改能够更清楚地传达我的意思,其中一个部分是我使用的变体(添加“ .FatRat”)不会失去精度。 - raiph
2
我今天添加了一个PR,引入了一个$*RAT-UPGRADE-CLASS动态变量,允许指示如何处理从Rat升级的方式:https://github.com/rakudo/rakudo/pull/4299。有了这个,当分母超过64位时,您可以在代码中省略`4.FatRat`,并添加`my $*RAT-UPGRADE-CLASS = FatRat(这将导致升级到FatRat而不是降级到Num`)。 - Elizabeth Mattijsen
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接