[Perl] 如何將數字換底

作者:   發佈於:   #perl

Perl 的數值,在其內部十進位來表示。若要將十進位數字轉成其他進位數字,可用以下的 to_base($base, $n) 函式。其處理對象 $n 是十位數字數值的純量變數。其傳回值也是一個純量變數。

use v5.40;

sub to_base ($base, $n) {
    state @digits = ('0'..'9', 'A'..'Z');

    die 'base argument is out of rage. Is: $base, should be 2..36'
        unless 2 <= $base <= 36;

    # Recursive calls on an inner-sub to avoid doing redundant
    # param-validations.
    return sub ($base, $n) {
        my $lsd = $digits[ $n % $base ];
        my $high = int($n / $base);
        return ($high > 0 ? __SUB__->($high, $base) : "") . $lsd;
    }->($n, $base);
}

而要將某個底數不是 10 的數字轉換成十進位的方式,可用以下的 from_base($base, $n) 函式。

use v5.40;

sub from_base ($base, $n) {
    state @digits = ('0'..'9', 'A'..'Z');
    state %decOf = map { $digits[$_] => $_ } (0..$#digits);

    die 'base argument is out of rage. Is: $base, should be 2..36'
        unless 2 <= $base <= 36;

    # Recursive calls on an inner-sub to avoid doing redundant
    # param-validations.
    return sub ($base, $n) {
        return 0 if $n eq "";
        my $lsd = substr($n, -1);
        my $high = substr($n, 0, -1);
        return $base * __SUB__->($base, $high) + $decOf{$lsd};
    }->($base, $n);
}

這兩個函式都是以遞迴演算法寫成的。同時,為了避免多次地對不會變動的 $base 做格式上的檢查,實際上遞迴的函式並非它們本體,而是其內部一個較小的無名函式。在 Perl 中可以使用 __SUB__ 來表示「目前這個函式」,所以無名函式也可以遞迴呼叫自己。