# Copyright (c) 2007-2009 Martin Becker. All rights reserved. # This package is free software; you can redistribute it and/or modify it # under the same terms as Perl itself. # # $Id: 03_expressions.t 39 2009-06-08 21:21:57Z demetri $ # Checking arithmetic operators and expressions. # Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl t/03_expressions.t' ######################### use strict; use warnings; use Test; BEGIN { plan tests => 202 }; use Math::Polynomial 1.000; ok(1); # module loaded ######################### sub has_coeff { my $p = shift; if (!ref($p) || !$p->isa('Math::Polynomial')) { print '# expected Math::Polynomial object, got ', ref($p)? ref($p): defined($p)? qq{"$p"}: 'undef', "\n"; return 0; } my @coeff = $p->coeff; if (@coeff != @_ || grep {$coeff[$_] != $_[$_]} 0..$#coeff) { print '# expected coefficients (', join(', ', @_), '), got (', join(', ', @coeff), ")\n"; return 0; } return 1; } my $p = Math::Polynomial->new(-0.25, 0, 1.25); my $q = $p->new(-0.25, 0, 0.25); my $r = $p->new(-1, 2); my $s = $p->new(0.5, 0.5); my $c = $p->new(-0.5); my $zp = $p->new; my $bool = !$p; ok(!$bool); # !p is false ok(defined $bool); # !p is defined $bool = !$c; ok(!$bool); # !c is false ok(defined $bool); # !c is defined ok($zp->degree < 0); # zp is the zero polynomial $bool = !$zp; ok($bool); # !zp is true $bool = 0; while ($p) { $bool = 1; last; } ok($bool); # p is true; $bool = 1; while ($zp) { $bool = 0; last; } ok($bool); # zp is false; ok(!$p->is_zero); ok($p->is_nonzero); ok($zp->is_zero); ok(!$zp->is_nonzero); my $pp = $p->new(-0.25, 0, 1.25); $bool = $p == $p; ok($bool); # p == p $bool = $p == $pp; ok($bool); # p == pp $bool = $p == $q; ok(!$bool); # not p == q ok(defined $bool); # defined p == q $bool = $p == $r; ok(!$bool); # not p == r ok(defined $bool); # defined p == r $bool = $p != $p; ok(!$bool); # not p != p ok(defined $bool); # defined p != p $bool = $p != $pp; ok(!$bool); # not p != pp ok(defined $bool); # defined p != pp $bool = $p != $q; ok($bool); # p != q $bool = $p != $r; ok($bool); # p != r my $qq = -$p; ok(has_coeff($qq, 0.25, 0, -1.25)); # -p $qq = -$zp; ok(has_coeff($qq)); # -0 $qq = $p + $q; ok(has_coeff($qq, -0.5, 0, 1.5)); # p + q $qq = $p + $r; ok(has_coeff($qq, -1.25, 2, 1.25)); # p + r $qq = $r + $p; ok(has_coeff($qq, -1.25, 2, 1.25)); # r + p $qq = $p + $zp; ok(has_coeff($qq, -0.25, 0, 1.25)); # p + 0 $qq = $zp + $p; ok(has_coeff($qq, -0.25, 0, 1.25)); # 0 + p $qq = $p - $q; ok(has_coeff($qq, 0, 0, 1)); # p - q $qq = $p - $pp; ok(has_coeff($qq)); # p - p $qq = $p - $r; ok(has_coeff($qq, 0.75, -2, 1.25)); # p - r $qq = $r - $p; ok(has_coeff($qq, -0.75, 2, -1.25)); # r - p $qq = $p - $zp; ok(has_coeff($qq, -0.25, 0, 1.25)); # p - 0 $qq = $zp - $p; ok(has_coeff($qq, 0.25, 0, -1.25)); # 0 - p $qq = $p * $q; ok(has_coeff($qq, 1/16, 0, -3/8, 0, 5/16)); # p * q $qq = $q * $p; ok(has_coeff($qq, 1/16, 0, -3/8, 0, 5/16)); # q * p $qq = $p * $r; ok(has_coeff($qq, 0.25, -0.5, -1.25, 2.5)); # p * r $qq = $r * $p; ok(has_coeff($qq, 0.25, -0.5, -1.25, 2.5)); # r * p $qq = $p * $c; ok(has_coeff($qq, 1/8, 0, -5/8)); # p * c $qq = $c * $p; ok(has_coeff($qq, 1/8, 0, -5/8)); # c * p $qq = $p * $zp; ok(has_coeff($qq)); # p * 0 $qq = $zp * $p; ok(has_coeff($qq)); # 0 * p $qq = $p / $q; ok(has_coeff($qq, 5)); # p / q $qq = $p / $r; ok(has_coeff($qq, 5/16, 5/8)); # p / r $qq = $p / $c; ok(has_coeff($qq, 0.5, 0, -2.5)); # p / c $qq = eval { $p / $zp }; ok(!defined $qq); # not defined p / 0 ok($@ =~ /division by zero polynomial/); $qq = $r / $p; ok(has_coeff($qq)); # r / p $qq = $r / $s; ok(has_coeff($qq, 4)); # r / s $qq = $c / $p; ok(has_coeff($qq)); # c / p $qq = $zp / $p; ok(has_coeff($qq)); # zp / p $qq = eval { $zp / $zp }; ok(!defined $qq); # not defined 0 / 0 ok($@ =~ /division by zero polynomial/); $qq = $p % $q; ok(has_coeff($qq, 1)); # p % q $qq = $p % $r; ok(has_coeff($qq, 1/16)); # p % r $qq = $p % $c; ok(has_coeff($qq)); # p % c $qq = eval { $p % $zp }; ok(!defined $qq); # not defined p % 0 ok($@ =~ /division by zero polynomial/); $qq = $r % $p; ok(has_coeff($qq, -1, 2)); # r % p $qq = $r % $s; ok(has_coeff($qq, -3)); # r % s $qq = $c % $p; ok(has_coeff($qq, -0.5)); # c % p $qq = $zp % $p; ok(has_coeff($qq)); # zp % p $qq = eval { $zp % $zp }; ok(!defined $qq); # not defined 0 % 0 ok($@ =~ /division by zero polynomial/); $qq = $p->mmod($q); ok(has_coeff($qq, 0.25)); # p mmod q $qq = $p->mmod($r); ok(has_coeff($qq, 0.25)); # p mmod r $qq = $p->mmod($c); ok(has_coeff($qq)); # p mmod c $qq = eval { $p->mmod($zp) }; ok(!defined $qq); # not defined p mmod 0 ok($@ =~ /division by zero polynomial/); $qq = $r->mmod($p); ok(has_coeff($qq, -1, 2)); # r mmod p $qq = $r->mmod($s); ok(has_coeff($qq, -1.5)); # r mmod s $qq = $c->mmod($p); ok(has_coeff($qq, -0.5)); # c mmod p $qq = $zp->mmod($p); ok(has_coeff($qq)); # zp mmod p $qq = eval { $zp->mmod($zp) }; ok(!defined $qq); # not defined 0 mmod 0 ok($@ =~ /division by zero polynomial/); my $rr; ($qq, $rr) = $p->divmod($q); ok(has_coeff($qq, 5)); # p / q ok(has_coeff($rr, 1)); # p % q ($qq, $rr) = $p->divmod($r); ok(has_coeff($qq, 5/16, 5/8)); # p / r ok(has_coeff($rr, 1/16)); # p % r ($qq, $rr) = $p->divmod($c); ok(has_coeff($qq, 0.5, 0, -2.5)); # p / c ok(has_coeff($rr)); # p % c ($qq, $rr) = eval { $p->divmod($zp) }; ok(!defined $qq); # not defined p / 0 ok(!defined $rr); # not defined p % 0 ok($@ =~ /division by zero polynomial/); ($qq, $rr) = $r->divmod($p); ok(has_coeff($qq)); # r / p ok(has_coeff($rr, -1, 2)); # r % p ($qq, $rr) = $r->divmod($s); ok(has_coeff($qq, 4)); # r / s ok(has_coeff($rr, -3)); # r % s ($qq, $rr) = $c->divmod($p); ok(has_coeff($qq)); # c / p ok(has_coeff($rr, -0.5)); # c % p ($qq, $rr) = $zp->divmod($p); ok(has_coeff($qq)); # zp / p ok(has_coeff($rr)); # zp % p ($qq, $rr) = eval { $zp->divmod($zp) }; ok(!defined $qq); # not defined 0 / 0 ok(!defined $rr); # not defined 0 % 0 ok($@ =~ /division by zero polynomial/); $qq = $p->add_const(0); ok(has_coeff($qq, -0.25, 0, 1.25)); # p + 0 $qq = $p->add_const(1); ok(has_coeff($qq, 0.75, 0, 1.25)); # p + 1 $qq = eval { $p + 1 }; ok(has_coeff($qq, 0.75, 0, 1.25)); # p + 1 $qq = eval { 1 + $p }; ok(has_coeff($qq, 0.75, 0, 1.25)); # 1 + p $qq = $p->sub_const(0); ok(has_coeff($qq, -0.25, 0, 1.25)); # p - 0 $qq = $p->sub_const(1); ok(has_coeff($qq, -1.25, 0, 1.25)); # p - 1 $qq = eval { $p - 1 }; ok(has_coeff($qq, -1.25, 0, 1.25)); # p - 1 $qq = eval { 1 - $p }; ok(has_coeff($qq, 1.25, 0, -1.25)); # 1 - p $qq = $zp->sub_const(1); ok(has_coeff($qq, -1)); # 0 - 1 $qq = $p->mul_const(0); ok(has_coeff($qq)); # p * 0 $qq = $p->mul_const(1); ok(has_coeff($qq, -0.25, 0, 1.25)); # p * 1 $qq = $p->mul_const(2); ok(has_coeff($qq, -0.5, 0, 2.5)); # p * 2 $qq = eval { $p->div_const(0) }; ok(!defined $qq); # not defined p / 0 ok($@ =~ /division by zero/); $qq = $p->div_const(1); ok(has_coeff($qq, -0.25, 0, 1.25)); # p / 1 $qq = $p->div_const(2); ok(has_coeff($qq, -1/8, 0, 5/8)); # p / 2 $qq = $p ** 0; ok(has_coeff($qq, 1)); # p ** 0 $qq = $p ** 1; ok(has_coeff($qq, -0.25, 0, 1.25)); # p ** 1 $qq = $p ** 2; ok(has_coeff($qq, 1/16, 0, -5/8, 0, 25/16)); # p ** 2 $qq = $p ** 3; ok(has_coeff($qq, -1/64, 0, 15/64, 0, -75/64, 0, 125/64)); # p ** 3 $qq = $c ** 0; ok(has_coeff($qq, 1)); # c ** 0 $qq = $c ** 1; ok(has_coeff($qq, -0.5)); # c ** 1 $qq = $c ** 2; ok(has_coeff($qq, 0.25)); # c ** 2 $qq = $c ** 3; ok(has_coeff($qq, -1/8)); # c ** 3 $qq = $zp ** 0; ok(has_coeff($qq, 1)); # 0 ** 0 $qq = $zp ** 1; ok(has_coeff($qq)); # 0 ** 1 $qq = $zp ** 2; ok(has_coeff($qq)); # 0 ** 2 $qq = $zp ** 3; ok(has_coeff($qq)); # 0 ** 3 $qq = eval { 3 ** $p }; ok(!defined $qq); # not defined 3 ** p ok($@ =~ /wrong operand type/); $qq = eval { $p ** 0.5 }; ok(!defined $qq); # not defined p ** 0.5 ok($@ =~ /non-negative integer argument expected/); $qq = eval { $p ** $p }; ok(!defined $qq); # not defined p ** p ok($@ =~ /non-negative integer argument expected/); $qq = $p->pow_mod(0, $q); ok(has_coeff($qq, 1)); # p ** 0 % q $qq = $p->pow_mod(1, $q); ok(has_coeff($qq, 1)); # p ** 1 % q $qq = $p->pow_mod(2, $q); ok(has_coeff($qq, 1)); # p ** 2 % q $qq = $p->pow_mod(3, $q); ok(has_coeff($qq, 1)); # p ** 3 % q $qq = $p->pow_mod(0, $r); ok(has_coeff($qq, 1)); # p ** 0 % r $qq = $p->pow_mod(1, $r); ok(has_coeff($qq, 1/16)); # p ** 1 % r $qq = $p->pow_mod(2, $r); ok(has_coeff($qq, 1/256)); # p ** 2 % r $qq = $p->pow_mod(0, $c); ok(has_coeff($qq)); # p ** 0 % c $qq = $p->pow_mod(1, $c); ok(has_coeff($qq)); # p ** 1 % c $qq = $p->pow_mod(2, $c); ok(has_coeff($qq)); # p ** 2 % c $qq = eval { $p->pow_mod(0, $zp) }; ok(!defined $qq); # not defined p ** 0 % 0 ok($@ =~ /division by zero polynomial/); $qq = eval { $p->pow_mod(1, $zp) }; ok(!defined $qq); # not defined p ** 1 % 0 ok($@ =~ /division by zero polynomial/); $qq = eval { $p->pow_mod(2, $zp) }; ok(!defined $qq); # not defined p ** 2 % 0 ok($@ =~ /division by zero polynomial/); $qq = $r->pow_mod(0, $q); ok(has_coeff($qq, 1)); # r ** 0 % q $qq = $r->pow_mod(1, $q); ok(has_coeff($qq, -1, 2)); # r ** 1 % q $qq = $r->pow_mod(2, $q); ok(has_coeff($qq, 5, -4)); # r ** 2 % q $qq = $r->pow_mod(3, $q); ok(has_coeff($qq, -13, 14)); # r ** 3 % q $qq = $c->pow_mod(0, $q); ok(has_coeff($qq, 1)); # c ** 0 % q $qq = $c->pow_mod(1, $q); ok(has_coeff($qq, -0.5)); # c ** 1 % q $qq = $c->pow_mod(2, $q); ok(has_coeff($qq, 0.25)); # c ** 2 % q $qq = $zp->pow_mod(0, $q); ok(has_coeff($qq, 1)); # 0 ** 0 % q $qq = $zp->pow_mod(1, $q); ok(has_coeff($qq)); # 0 ** 1 % q $qq = $zp->pow_mod(2, $q); ok(has_coeff($qq)); # 0 ** 2 % q $qq = eval { $zp->pow_mod(0, $zp) }; ok(!defined $qq); # not defined 0 ** 0 % 0 ok($@ =~ /division by zero polynomial/); $qq = eval { $zp->pow_mod(1, $zp) }; ok(!defined $qq); # not defined 0 ** 1 % 0 ok($@ =~ /division by zero polynomial/); $qq = eval { $zp->pow_mod(2, $zp) }; ok(!defined $qq); # not defined 0 ** 2 % 0 ok($@ =~ /division by zero polynomial/); $qq = $p << 3; ok(has_coeff($qq, 0, 0, 0, -0.25, 0, 1.25)); # p << 3 $qq = $c << 3; ok(has_coeff($qq, 0, 0, 0, -0.5)); # c << 3 $qq = $zp << 3; ok(has_coeff($qq)); # 0 << 3 $qq = $p << 0; ok(has_coeff($qq, -0.25, 0, 1.25)); # p << 0 $qq = $zp << 0; ok(has_coeff($qq)); # 0 << 0 $qq = $p >> 3; ok(has_coeff($qq)); # p >> 3 $qq = $p >> 2; ok(has_coeff($qq, 1.25)); # p >> 2 $qq = $p >> 0; ok(has_coeff($qq, -0.25, 0, 1.25)); # p >> 0 $qq = $zp >> 2; ok(has_coeff($qq)); # 0 >> 0 $qq = $zp >> 0; ok(has_coeff($qq)); # 0 >> 0 $pp = $p->new(11, 22, 33, 44, 55); my $ok = 1; foreach my $w (0..6) { foreach my $b (0..6) { my @c = grep {defined $_} (11, 22, 33, 44, 55)[$b..$b+$w-1]; $qq = $pp->slice($b, $w); $ok ||= has_coeff($qq, @c); } } ok($ok); # slice $qq = $p->nest($q); ok(has_coeff($qq, -11/64, 0, -5/32, 0, 5/64)); # p(q) $qq = $q->nest($p); ok(has_coeff($qq, -15/64, 0, -5/32, 0, 25/64)); # q(p) $qq = $p->nest($zp); ok(has_coeff($qq, -0.25)); # q(0) $qq = $zp->nest($p); ok(has_coeff($qq)); # 0(p) $bool = $q->is_monic; ok(!$bool); # q is not monic $pp = $q->monize; ok(has_coeff($pp, -1, 0, 1)); # monize q $bool = $pp->is_monic; ok($bool); # x**2-1 is monic $qq = $pp->monize; ok($qq == $pp); # monize monic pp $qq = $c->monize; ok(has_coeff($qq, 1)); # monize c $qq = eval { $zp->monize }; ok(has_coeff($qq)); # monize 0 $bool = $zp->is_monic; ok(defined $bool); # is_monic defined for zp ok(!$bool); # zp is not monic # assignment operators $pp = Math::Polynomial->new(1, 10); $qq = $pp; $pp += $pp; ok(has_coeff($pp, 2, 20)); # += working ok(has_coeff($qq, 1, 10)); # += no side effects $pp = $p && $q; ok($pp == $q); # && operator long path $pp = $zp && $q; ok($pp == $zp); # && operator short path $pp = $p || $q; ok($pp == $p); # || operator short path $pp = $zp || $q; ok($pp == $q); # || operator long path # diagnostics ok(10_000 == $Math::Polynomial::max_degree); $Math::Polynomial::max_degree = 9; $pp = $p->new(0, -1, 0, 1); $qq = eval { $pp ** 3 }; ok(has_coeff($qq, 0, 0, 0, -1, 0, 3, 0, -3, 0, 1)); $pp = $p->new(0, 4, 0, -5, 0, 1); $qq = eval { $pp ** 2 }; ok(!defined($qq) && $@ && $@ =~ /exponent too large/); $qq = eval { local $Math::Polynomial::max_degree; $pp ** 2 }; ok(defined($qq) && $q->isa('Math::Polynomial')); $qq = eval { $pp << 4 }; ok(has_coeff($qq, 0, 0, 0, 0, 0, 4, 0, -5, 0, 1)); $qq = eval { $pp << 5 }; ok(!defined($qq) && $@ && $@ =~ /exponent too large/); $qq = eval { local $Math::Polynomial::max_degree; $pp << 5 }; ok(defined($qq) && $q->isa('Math::Polynomial')); $qq = eval { $p->divmod($p) }; ok(!defined($qq) && $@ && $@ =~ /array context required/); __END__