在转到 Real 角色的第二部分之前,让我们停下来研究一下 Int 类的中的 polymod
方法。
该方法接收一个数字和任意数字(单位)的列表并返回相应的乘数。所以,你可以很容易地说,例如 550 秒,是 9分 10 秒:
> 550.polymod(60)
(10 9)
在方法调用中,60 的值是一分钟内的秒数。结果中,9 是分钟数,10 是余数,其为秒数。所以,550 秒= 10 秒 + 9 分钟。
如果你想了解更多细节,请添加更多单位。例如,什么是 32768 秒?
> 32768.polymod(60, 60, 24)
(8 6 9 0)
这是 8 秒,6 分钟,9 小时和 0 天。
类似地,132768 秒是 1 天,12 小时,52 分钟和 48 秒:
> 132768.polymod(60, 60, 24)
(48 52 12 1)
老实说,我很难理解它是如何工作的,以及如何读取结果。
文档中的另一个例子更加难以理解:
> 120.polymod(1, 10, 100)
(0 0 12 0)
12 是什么意思?这显然是12倍10.好吧,但我要求给我一些关于数百的信息。我的期望是这样的:120 是 10 的二倍加上 100 的一倍。
试试 121:
> 121.polymod(1, 10)
(0 1 12)
呃,为什么是零?零加上 1x1 加上 12x10? BRR。啊!您不需要在参数中显示地指定 1:
> 121.polymod(10)
(1 12)
这更有意义。除了我还不知道 121 中有几个 100 的事实:
> 121.polymod(10, 100)
(1 12 0)
> 121.polymod(100, 10)
(21 1 0)
现在是时候看看源代码( src/core/Int.pm
)了:
method polymod(Int:D: +@mods) {
fail X::OutOfRange.new(
:what('invocant to polymod'), :got(self), :range<0..^Inf>
) if self < 0;
gather {
my $more = self;
if @mods.is-lazy {
for @mods -> $mod {
$more
?? $mod
?? take $more mod $mod
!! Failure.new(X::Numeric::DivideByZero.new:
using => 'polymod', numerator => $more)
!! last;
$more = $more div $mod;
}
take $more if $more;
}
else {
for @mods -> $mod {
$mod
?? take $more mod $mod
!! Failure.new(X::Numeric::DivideByZero.new:
using => 'polymod', numerator => $more);
$more = $more div $mod;
}
take $more;
}
}
}
该方法有两个分支,一个用于惰性列表,另一个用于非惰性列表。现在让我们只关注第二个分支:
for @mods -> $mod {
$mod
?? take $more mod $mod
!! Failure.new(X::Numeric::DivideByZero.new:
using => 'polymod', numerator => $more);
$more = $more div $mod;
}
take $more;
好吧,最后一个 take
接收余数,这很容易。在循环中,您将数字除以下一个单位,然后对中间余数进行 “计数”。
我会说我会以不同的方式实现它并切换操作符:
for @mods -> $mod {
$mod
- ?? take $more mod $mod
+ ?? take $more div $div
!! Failure.new(X::Numeric::DivideByZero.new:
using => 'polymod', numerator => $more);
- $more = $more div $mod;
+ $more = $more mod $mod;
}
take $more;
通过这段代码,我可以得到 121 中有几个一百,几个十和几个一:
> 121.polymod(100, 10, 1)
(1 2 1 0)
好的,让我们避免两个 1:
> 1234.polymod(1000, 100, 10, 1)
(1 2 3 4 0)
前面的例子中秒数也可以正常工作:
> 132768.polymod(86400, 3600, 60)
(1 12 52 48)
这是 1 天,12 小时,52 分钟和 48 秒。
正如你所看到的,现在你必须使用明确的单位(8600 而不是 24),你必须按照降序对它们进行排序,但是现在我可以理解和解释结果,而这在原始方法中几乎是不可能的。