use strict;
use feature 'say';
use POSIX qw(floor);
use ntheory qw/fromdigits todigits/;

sub encode {
    my($n, $b) = @_;
    my @out;
    my $r = 0;

    while ($n) {
        $r = $n % $b;
        $n = floor $n/$b;
        $n += 1, $r -= $b if $r < 0;
        push @out, todigits($r, -$b) || 0;
    }
    join '', reverse @out;
}

sub decode {
    my($s, $b) = @_;
    my $total = 0;
    my $i = 0;
    for my $c (reverse split '', $s) {
        $total += (fromdigits($c, -$b) * $b**$i);
        $i++;
    }
    $total
}

say ' 10 in base  -2: ', encode(10, -2);
say ' 15 in base -10: ', encode(15, -10);
say '146 in base  -3: ', encode(146, -3);
say '';
say  '11110 from base  -2: ', decode("11110", -2);
say  '21102 from base  -3: ', decode("21102", -3);
say  '  195 from base -10: ', decode("195",  -10);