Perl 6 中的 .polymod 方法 - 把數(shù)字分解成分母
命名
.polymod
方法接受幾個除數(shù)并把它的調(diào)用者分解成一份一份的:
my $seconds = 1 * 60*60*24 # days
+ 3 * 60*60 # hours
+ 4 * 60 # minutes
+ 5; # seconds
say $seconds.polymod: 60, 60;
say $seconds.polymod: 60, 60, 24;
# OUTPUT:
# (5 4 27)
# (5 4 3 1)
這種情況下我們作為參數(shù)傳遞的除數(shù)是和時間相關(guān)的: 60(每分鐘有多少秒)揭厚, 60(每小時有多少分鐘)框仔,和24(每天有多少小時)捶朵。從最小的單位開始挺份, 我們一直前進到最大的單位浓若。
輸出和輸入的除數(shù)是相匹配的 - 從最小的單位到最大的單位: 5 秒茅坛,4 分鐘观挎,3 小時和 1 天挪凑。
手工制作
不使用 .polymod
而使用一個循環(huán)來展示怎么之前的計算:
my $seconds = 2 * 60*60*24 # days
+ 3 * 60*60 # hours
+ 4 * 60 # minutes
+ 5; # seconds
my @pieces;
for 60, 60, 24 -> $divisor {
@pieces.push: $seconds mod $divisor;
$seconds div= $divisor
}
@pieces.push: $seconds;
say @pieces;
# OUTPUT:
# [5 4 3 2]
超越無限
當除數(shù)是以惰性列表的形式傳遞給 .polymod
方法時荠瘪,它會一直運行直到余數(shù)為零并不會遍歷整個列表:
say 120.polymod: 101, 102, 103, 10?, 10?;
say 120.polymod: lazy 101, 102, 103, 10?, 10?;
say 120.polymod: 101, 102, 103 … ∞;
# OUTPUT:
# (0 12 0 0 0 0)
# (0 12)
# (0 12)
在第一個調(diào)用中夯巷, 我們讓一系列數(shù)字按 10 的冪增長。該調(diào)用的輸出包含了 4 個尾部的零哀墓,因為 .polymod
方法計算了每個除數(shù)趁餐。在第二個調(diào)用中,我們使用 lazy
關(guān)鍵字顯式地創(chuàng)建了一個惰性列表篮绰, 而現(xiàn)在我們在返回的列表中只有 2 個條目后雷。
第一個除數(shù)(10)結(jié)果余數(shù)為 0,這是返回列表中的第一個條目吠各,對于下一個除數(shù)臀突,整除把我們的 120 變成了 12。12 除以 100 的余數(shù)為 12贾漏, 它是返回列表中的第二個條目候学。 現(xiàn)在, 12 整除 100 為 0纵散, 它終止了 .polymod
的執(zhí)行并給了我們兩個 條目的結(jié)果梳码。
在最后一個調(diào)用中,我們使用了省略號伍掀,它是一個序列操作符掰茶,用來創(chuàng)建一系列按 10 的冪增長的數(shù)字,但是這一次序列是無限的硕盹。因為它是惰性的符匾,結(jié)果再一次只有 2 個元素。
Zip It, Lock It, Put It In The Pocket
單獨的數(shù)字很好但是對于它們所代表的單位不夠具有描述性瘩例。我們來使用 Zip 元操作符:
my @units = <ng μg mg g kg>;
my @pieces = 42_666_555_444_333.polymod: 103 xx ∞;
say @pieces Z~ @units;
# OUTPUT:
# (333ng 444μg 555mg 666g 42kg)
快速命名
對于被調(diào)用者和除數(shù)啊胶,你不僅僅限于使用 Ints,也可以使用其它類型的數(shù)字垛贤。
say ?.polymod: ?;
say 5.Rat.polymod: .3, .2;
say 3.Rat.polymod: ?, ?;
# OUTPUT:
# (0 2)
# (0.2 0 80)
# (0.333333 0 12)
say 5.Num.polymod: .3, .2;
say 3.Num.polymod: ?, ?;
# OUTPUT:
# (0.2 0.199999999999999 79)
# (0.333333333333333 2.22044604925031e-16 12)
使用 Number::Denominate 模塊
use Number::Denominate;
my $seconds = 1 * 60*60*24 # days
+ 3 * 60*60 # hours
+ 4 * 60 # minutes
+ 5; # seconds
say denominate $seconds;
say denominate $seconds, :set<weight>;
# OUTPUT:
# 1 day, 3 hours, 4 minutes, and 5 seconds
# 97 kilograms and 445 grams
你還可以定義自己的單位:
say denominate 449, :units( foo => 3, <bar boors> => 32, 'ber' );
# OUTPUT:
# 4 foos, 2 boors, and 1 ber