Писал на перле несколько месяцев назад такой код. Выложу, может, пригодится для понимания.
Код:
#!/usr/bin/perl
use strict 'vars';
use warnings;
#use diagnostics;
sub check_number ($$);
sub find_char ($\@);
sub base_convert ($$$);
sub int_convert10 ($$$);
die "wrong param count\n" unless scalar @ARGV == 3;
my (%qry, $int, $frac);
$qry{'txt'} = shift || '72.01';#'1011101010111010';
$qry{'from'} = shift || 8;
$qry{'to'} = shift || 10;
$qry{'to'} =~ s/[^0-9]//g;
$qry{'from'} =~ s/[^0-9]//g;
if ($qry{'txt'} =~ /^(.+?)\.(.+?)$/) {
($int, $frac) = ($1, $2);
#print "NUMBERS: ", $int, " ", $frac, "\n";
} else {
$int = $qry{'txt'};
$frac = 0;
}
die "Wrong number: integer: " unless check_number $int, $qry{'from'};
if ($frac) {
die "Wrong number: fraction" unless check_number $frac, $qry{'from'};
}
($int, $frac) = base_convert ($qry{'txt'}, $qry{'from'}, $qry{'to'});
print "RESULT: $int.$frac\n";
#$qry{'txt'} =~ s/[^0-9a-f]//g;
exit 0;
sub check_number ($$) {
my ($num, $ss) = @_;
my ($i, $b, @chars, $d);
for $i (0 .. $ss - 1) {
$chars[$i] = ($i < 10 ? $i : chr ($i + 0x57));
}
$b = 1;
foreach $d (split //, $num) {
if (!find_char ($d, @chars) == 1) {
$b = 0;
last;
}
}
return $b;
}
sub find_char ($\@) {
my ($char, $arr) = @_;
my ($elem, $b);
$b = 0;
foreach $elem (@$arr) {
if ($char eq $elem) {
$b = 1;
last;
}
}
return $b;
}
sub base_convert ($$$) {
my ($num, $from, $to) = @_;
my ($int, $frac, $res);
#print $num, "\n";
if ($num =~ /^(.+?)\.(.+?)$/) {
($int, $frac) = ($1, $2);
} else {
$int = $num;
$frac = 0;
}
#print $frac, "\n";
if ($from != 10) {
$int = int_convert10 ($int, $from, 1) if $int;
$frac = int_convert10 ($frac, $from, 0) if $frac;
}
print "DEC: $int $frac\n";
$int = int_convert ($int, $to, 1) if $int;
$frac = int_convert ($frac, $to, 0) if $frac;
return ($int, $frac);
}
sub int_convert10 ($$$) {
my ($num, $from, $isint) = @_;
my ($j, $res, $i, @digit);
#print "NUM: ", $num, "\n";
@digit = split //, $num;
$j = $#digit;
if ($isint) {
for $i (0 .. $#digit) {
if ($digit[$i] =~ /^\d{1}$/) {
$res += $digit[$i] * $from ** $j--;
} else {
$res += (ord ($digit[$i]) - 0x57) * $from ** $j--;
}
}
} else {
for $i (0 .. $#digit) {
if ($digit[$i] =~ /^\d{1}$/) {
$res += $digit[$i] / ($from ** ($i + 1));
#print $digit[$i], "\n";
} else {
$res += (ord ($digit[$i]) - 0x57) / ($from ** ($i + 1));
}
}
}
$res =~ s/^0\.//;
#print "RES: ", $res, "\n";
return $res;
}
sub int_convert ($$$) {
my ($num, $to, $isint) = @_;
my ($ost, $res, $cnt);
#print $num, "\n";
if ($isint) {
while ($num > 0) {
$ost = $num % $to;
if ($ost < 10) {
$res .= $ost;
} else {
$res .= chr ($ost + 0x57);
}
$num = int ($num / $to);
}
$res = join '', reverse (split //, $res);
#print $res, "\n";
} else {
$num = '0.' . $num;
$ost = 1;
$cnt = 0;
#print $num, "\n";
while (($ost > 0) && ($cnt < 9)) {
#print "\n=======\n", $num, "\n";
$num *= $to;
#print $num, "\n";
$ost = $num - int ($num);
#print $ost, "\n";
if (int ($num) < 10) {
$res .= int ($num);
} else {
$res .= chr (int ($num) + 0x57);
}
#print $res, "\n";
$num = $ost;
#print $num, "\n";
$cnt++;
}
#$res = $res;
#print $res, "\n";
}
return $res;
}
|