【问题标题】:why is this memoized Euler14 implementation so much slower in Raku than Python?为什么这个记忆化的 Euler14 实现在 Raku 中比 Python 慢得多?
【发布时间】:2023-04-07 06:03:01
【问题描述】:

我最近在玩problem 14 中的Euler project1..1_000_000 范围内的哪个数字产生最长的Collatz sequence

我知道必须memoize 才能获得合理时间的问题,下面的Python 代码使用该技术相对较快地返回答案(记忆到字典):

#!/usr/bin/env python

L = 1_000_000
cllens={1:1}

cltz = lambda n: 3*n + 1 if n%2 else n//2

def cllen(n):
    if n not in cllens: cllens[n] = cllen(cltz(n)) + 1
    return cllens[n]

maxn=1
for i in range(1,L+1):
    ln=cllen(i)
    if (ln > cllens[maxn]): maxn=i

print(maxn)

(改编自here;我更喜欢这个不使用max 的版本,因为我可能想修改它以返回最长的10 个序列等)。

我已尝试将其翻译为Raku,尽可能在语义上接近:

#!/usr/bin/env perl6
use v6;

my $L=1_000_000;
my %cllens = (1 => 1);

sub cltz($n) { ($n %% 2) ?? ($n div 2) !! (3*$n+1) }

sub cllen($n) {
    (! %cllens{$n}) && (%cllens{$n} = 1+cllen($n.&cltz));
    %cllens{$n};
}

my $maxn=1;
for (1..$L) {
    my $ln = cllen($_);
    ($ln > %cllens{$maxn}) && ($maxn = $_)
}
say $maxn

以下是我一直在运行这些的各种时间:

$ time <python script>
837799

real    0m1.244s
user    0m1.179s
sys     0m0.064s

另一方面,在Raku

$ time <raku script>
837799

real    0m21.828s
user    0m21.677s
sys     0m0.228s

问题

我是不是在两者之间翻译错误,或者差异是启动 VM 等不可调和的问题?

我可以对Raku 代码应用一些巧妙的调整/习语来大大加快它的速度吗?

一边

当然,这与这个特定的Euler project 问题无关;我更感兴趣的是是否有任何适合Raku的神奇加速奥术我不知道。

【问题讨论】:

  • 也许获得 Raku “神奇加速”的 最佳 方法是将其翻译成 Python :-) 抱歉,无法抗拒,我已经很久没有使用 Perl,我可能无法提供 有用的 答案,除了可能在您的代码中插入时间陷阱以查看延迟在哪里。
  • :-) 很公平,但这并没有减损我对这里实际发生的事情的内在兴趣。
  • grobber,同意,我不是说你的问题无效,实际上很好。
  • @paxdiablo, .@grobber “也许最好的 方法来获得 Raku “神奇的加速”是将它翻译成 Python ...我可能无法提供有用答案”。 :-) 你有! :) Raku(do) 支持卓越的自动翻译系统。通过Inline 只需直接 使用现有的(或新的)外语代码(无需手动 翻译)。使用外来功能,就好像它们是 Raku 的原生功能一样!所有数据、异常等都会自动编组。如果您单击该链接,您将看到正在开发的Inline::Python。试试看?
  • 可能会看到使用“使用实验性:缓存”功能的改进。

标签:
python
raku
memoization
collatz