0

数値を 8 文字の英数字文字列にエンコードする方法Perlアルファベットで始まり、最後の数字がチェック ディジットである数字で終わる。

21767823360したがって、チェック ディジットを生成する方法と、結果の文字列が で始まるようにカウンターを開始することを計画しましA000000たが、perl は計算にそれほど大きな数を使用していません。

解決策を提案してください。

$AppID=alphanumero($appid,8,1);

sub alphanumero{
my ($n,$length,$type)=@_;
my @to_b36 = (0 .. 9, 'A' .. 'Z');
use integer;  # so that /= 36 is easy
my $u=$n%10;$n=21767823360+($n-$u)/10;
my $t = "";do { $t = $to_b36[$n % 36] . $t, $n /= 36 } while $n;
return "$t$u";
}
4

1 に答える 1

4

Perlは大きな数に関してはほとんど問題がありません、そしてあなたの数が本当に巨大であるなら、ただuse bignum。これにより、無限精度の演算が透過的に可能になります。

あなたの番号21767823360は約35ビットを必要とします。私perlは64ビット整数で構築されているので(perl -vサポートを確認するために参照)、あなたの数は私にとって「大きすぎ」ません。

数値を基数nに変換するアルゴリズムは単純です。

# pseudocode
let "digits"         be the array containing all the digits of our representation.
                       # the size of digits is the base of our new representation
                       # the digits are sorted in ascending order.
                       #digits[0] is zero.
var "n"              is the number we want to represent.
var "size"           is the number of digits of the new representation.
                       # floor(ln(n)/ln(digits.size))
var "representation" is the empty string.
while size >= 0:
  representation ← representation.concat(digits[n / digits.length ^ size]).
  n              ← n.modulo(digits.length ^ size).
  size           ← size - 1.
return representation.

Perlの例:

#!/usr/bin/perl
use strict; use warnings;
use Carp;

sub base_n {
  my ($number, $base, $max_digits, $pad) = @_;
  defined $number or croak "Undefined number for base_n";
  $number == int $number and $number >= 0
                  or croak "The number has to be a natural number for base_n";
  defined $base   or croak "Undefined base for base_n";
  $base == int $base and $base > 0
                  or croak "The base has to be a positive integer for base_n";

  my @digits = (0 .. 9, "A" .. "Z");
  $base <= @digits or croak "base_n can only convert to base-" . @digits . " max.";
  @digits = @digits[0 .. $base - 1];

  my $size = $number ? int(log($number) / log($base)) : 0; # avoid log(0)
  if (defined $max_digits) {
    $size < $max_digits
        or croak "The number $number is too large for $max_digits digits in base $base.";
    $size = $max_digits - 1 if $pad;
  }

  my $representation = "";
  while ($size >= 0) {
    $representation .= $digits[$number / @digits**$size];
    $number         %= @digits**$size;
    $size--;
  }

  if (wantarray) {
    my $checksum = substr $representation, -1;
    return $representation, $checksum;
  } else {
    return $representation;
  }
}

対応する(ただし不完全な)単体テスト:

use Test::More;
my $n = 21767823360;
ok "A000000" eq base_n($n => 36),        "simple";
ok "A000000" eq base_n($n => 36, 8),     "valid constraint";
ok "0A000000" eq base_n($n => 36, 8, 1), "padding";
ok ! eval { base_n($n => 36, 6); 1 },    "invalid constraint";
ok "0" eq (base_n($n => 36))[1],         "checksum (1)";
ok "A" eq (base_n($n+10 => 36))[1],      "checksum (2)";
ok "0" eq base_n(0 => 36),               "zero: simple";
ok "0"x8 eq base_n(0 => 36, 8, 1),       "zero: padding";
ok ! eval { base_n($n => 0.7); 1 },      "invalid base";
ok ! eval { base_n(0.7 => 36); 1 },      "invalid number";
ok $n == base_n($n => 10),               "round-trip safety";
ok $n eq base_n($n => 10, length $n, 1), "round-trip safety: padding";
done_testing;
于 2013-01-05T17:13:49.610 に答える