package Poly;
use overload
'+' => \&add,
'-' => \&add,
'*' => \&mul,
'%' => sub {$_[2] ? mod($_[1], $_[0]) : mod($_[0], $_[1])},
'/' => sub { $_[2] ? scalar(div($_[1], $_[0]))
: scalar(div($_[0], $_[1])) },
'<=>' => sub {$_[2] ? pcmp($_[1], $_[0]) : pcmp($_[0], $_[1])},
'""' => \&str
;
use Carp;
sub new {
my $this = shift;
my $class = ref($this) || $this;
my(@x) = @_;
return bless [norm(@x)], $class;
}
sub pretty {
my(@x) = @{+shift};
my $n = @x;
local $_;
return "0" if !@x;
return join " + ", map {$n--; $_ ? ("x^$n") : ()} @x;
}
sub print {
my $self = shift;
print $self->pretty, "\n";
}
sub order {
my $self = shift;
return $}
sub str {
return overload::StrVal($_[0]);
}
sub norm {
my(@x) = @_;
shift @x while @x && !$x[0];
return @x;
}
sub multerm {
my($self, $n) = @_;
return $self->new(@$self, (0) x $n);
}
sub pcmp {
my @x = @{+shift};
my @y = @{+shift};
return @x <=> @y;
}
sub powers2poly
{
my $self = shift;
my $poly = $self->new;
my $n;
foreach $n (@_) {
$poly += $one->multerm($n);
}
return $poly;
}
sub add {
my $self = shift;
my @x = @$self;
my @y = @{+shift};
my @r;
unshift @r, (pop @x || 0) ^ (pop @y || 0)
while @x || @y;
return $self->new(@r);
}
sub mul {
my($self) = shift;
my @y = @{+shift};
my $r = $self->new;
my $power = 0;
while (@y) {
$r += $self->multerm($power) if pop @y;
$power++;
}
return $r;
}
sub oldmod {
my($self, $div) = @_;
my @num = @$self;
my @div = @$div;
my $r = $self->new(splice @num, 0, @div);
do {
push @$r, shift @num while @num && $r < $div;
$r += $div if $r >= $div;
} while @num;
return $r;
}
sub div {
my($self, $div) = @_;
my $q = $self->new;
my $r = $self->new(@$self);
my $one = $self->new(1);
my ($tp, $power);
croak "divide by zero" if !@$div;
while ($div <= $r) {
$power = 0;
$power++ while ($tp = $div->multerm($power)) < $r;
$q += $one->multerm($power);
$r -= $tp;
}
return wantarray ? ($q, $r) : $q;
}
sub mod {
(&div)[1];
}
sub hex {
my @x = @{+shift};
my $minwidth = shift || 32;
unshift @x, 0 while @x % 8 || @x < $minwidth;
return unpack "H*", pack "B*", join "", @x;
}
sub revhex {
my @x = @{+shift};
my $minwidth = shift || 32;
unshift @x, 0 while @x % 8 || @x < $minwidth;
return unpack "H*", pack "B*", join "", reverse @x;
}
$one = Poly->new(1);
1;