########################################################## ## This file is PGpolynomialmacros.pl ## ## It contains rountines used to create and manipulate ## ## polynomials for WeBWorK ## ## ## ## Copyright 2002 Mark Schmitt ## ## Version 1.1.2 ## ########################################################## ## In the current version, there is no attempt to verify that correct arrays are being passed to the routines. ## This ought to be changed in the next incarnation. ## It is assumed that arrays passed to the routines have no leading zeros, and represent the coefficients of ## a polynomial written in standard form using place-holding zeros. ## This means $array[0] is the leading coefficient of the polynomial and $array[$#array] is the constant term. ## ## The routines were written based on the needs of my Honors Algebra 2 course. The following algorithms have been ## coded: ## Polynomial Multiplication ## Polynomial Long Division ## Polynomial Synthetic Division (mainly as a support routine for checking bounds on roots) ## Finding the least positive integral upper bounds for roots ## Finding the greatest negative integral lower bounds for roots ## Descartes' Rule of Signs for the maximum number of positive and negative roots ## Stringification : converting an array of coefficients into a properly formatted polynomial string ## Polynomial Addition ## Polynomial Subtraction ## ## ValidPoly ## sub ValidPoly { my $xref = @_; if (${$xref}[0] != 0) {return 1;} else {return 0;} } sub PolyAdd{ my ($xref,$yref) = @_; @local_x = @{$xref}; @local_y = @{$yref}; if ($#local_x < $#local_y) { while ($#local_x < $#local_y) {unshift @local_x, 0;} } elsif ($#local_y < $#local_x) { while ($#local_y < $#local_x) {unshift @local_y, 0;} } foreach $i (0..$#local_x) { $sum[$i] = $local_x[$i] + $local_y[$i]; } return @sum; } sub PolySub{ my ($xref,$yref) = @_; @local_x = @{$xref}; @local_y = @{$yref}; if ($#local_x < $#local_y) { while ($#local_x < $#local_y) {unshift @local_x, 0;} } elsif ($#local_y < $#local_x) { while ($#local_y < $#local_x) {unshift @local_y, 0;} } foreach $i (0..$#local_x) { $diff[$i] = $local_x[$i] - $local_y[$i]; } return @diff; } ## ## @newPoly = PolyMult(~~@coefficientArray1,~~@coefficientArray2); ## ## accepts two arrays containing coefficients in descending order ## returns an array with the coefficients of the product ## sub PolyMult{ my ($xref,$yref) = @_; @local_x = @{$xref}; @local_y = @{$yref}; foreach $i (0..$#local_x + $#local_y) {$result[$i] = 0;} foreach $i (0..$#local_x) { foreach $j (0..$#local_y) { $result[$i+$j] = $result[$i+$j]+$local_x[$i]*$local_y[$j]; } } return @result; } ## ## (@quotient,$remainder) = SynDiv(~~@dividend,~~@divisor); ## sub SynDiv{ my ($dividendref,$divisorref)=@_; my @dividend = @{$dividendref}; my @divisor = @{$divisorref}; my @quotient; $quotient[0] = $dividend[0]; foreach $i (1..$#dividend) { $quotient[$i] = $dividend[$i]-$quotient[$i-1]*$divisor[1]; } return @quotient; } ## ## ## ## ## sub LongDiv{ my ($dividendref,$divisorref)=@_; my @dividend = @{$dividendref}; my @divisor = @{$divisorref}; my @quotient; my @remainder; foreach $i (0..$#dividend-$#divisor) { $quotient[$i] = $dividend[$i]/$divisor[0]; foreach $j (1..$#divisor) { $dividend[$i+$j] = $dividend[$i+$j] - $quotient[$i]*$divisor[$j]; } } foreach $i ($#dividend-$#divisor+1..$#dividend) { $remainder[$i-($#dividend-$#divisor+1)] = $dividend[$i]; } return (\@quotient,\@remainder); } ## ## $upperBound = UpBound(~~@polynomial); ## ## accepts a reference to an array containing the coefficients, in descending ## order, of a polynomial. ## ## returns the lowest positive integral upper bound to the roots of the ## polynomial ## sub UpBound { my $polyref=$_[0]; my @poly = @{$polyref}; my $bound = 0; my $test = 0; while ($test < @poly) { $bound++; $test=0; @div = (1,-$bound); @result = &SynDiv(\@poly,\@div); foreach $i (0..$#result) { if (sgn($result[$i])==sgn($result[0]) || $result[$i]==0) { $test++; } } } return $bound; } ## ## $lowerBound = LowBound(~~@polynomial); ## ## accepts a reference to an array containing the coefficients, in descending ## order, of a polynomial. ## ## returns the greatest negative integral lower bound to the roots of the ## polynomial ## sub LowBound { my $polyref=$_[0]; my @poly = @{$polyref}; my $bound = 0; my $test = 0; while ($test == 0) { $test = 1; $bound = $bound-1; @div = (1,-$bound); @res = &SynDiv(\@poly,\@div); foreach $i (1..int(($#res -1)/2)) { if (sgn($res[0])*sgn($res[2*$i]) == -1) { $test = 0;} } foreach $i (1..int($#res/2)) { if (sgn($res[0])*sgn($res[2*$i-1]) == 1) { $test = 0;} } } return $bound; } ## ## $string = PolyString(~~@coefficientArray,x); ## ## accepts an array containing the coefficients of a polynomial ## in descending order ## returns a sting containing the polynomial with variable v ## default variable is x ## sub PolyString{ my $temp = $_[0]; my @poly = @{$temp}; $string = ""; foreach $i (0..$#poly) { $j = $#poly-$i; if ($j == $#poly) {if ($poly[$i]!=1){ $string = $string."$poly[$i] x^{$j}";} else {$string=$string."x^{$j}";} } elsif ($j > 0 && $j!=1) { if ($poly[$i] >0) { if ($poly[$i]!=1){ $string = $string."+$poly[$i] x^{$j}";} else {$string = $string."+x^{$j}";}} elsif ($poly[$i] == 0) {} elsif ($poly[$i] == -1) {$string=$string."-x^{$j}";} else {$string = $string."$poly[$i] x^{$j}";} } elsif ($j == 1) { if ($poly[$i] > 0){ if ($poly[$i]!=1){ $string = $string."+$poly[$i] x";} else {$string = $string."+x";}} elsif ($poly[$i] == 0) {} elsif ($poly[$i] == -1){$string=$string."-x";} else {$string=$string."$poly[$i] x";} } else { if ($poly[$i] > 0){ $string = $string."+$poly[$i] ";} elsif ($poly[$i] == 0) {} else {$string=$string."$poly[$i] ";} } } return $string; } sub PolyFunc { my $temp = $_[0]; my @poly = @{$temp}; $func = ""; foreach $i (0..$#poly) { $j = $#poly-$i; if ($poly[$i] > 0) {$func = $func."+$poly[$i]*x**($j)";} else {$func = $func."$poly[$i]*x**($j)";} } return $func; } ## ## ($maxpos,$maxneg) = Descartes(~~@poly); ## ## accepts an array containing the coefficients, in descending order, of a ## polynomial ## returns the maximum number of positive and negative roots according to ## Descartes Rule of Signs ## ## IMPORTANT NOTE: this function currently does not accept coefficients of ## zero. ## sub Descartes { my $temp = $_[0]; my @poly = @{$temp}; my $pos = 0; my $neg = 0; foreach $i (1..$#poly) { if (sgn($poly[$i])*sgn($poly[$i-1]) == -1) {$pos++;} elsif (sgn($poly[$i])*sgn($poly[$i-1]) == 1) {$neg++;} } return ($pos,$neg); } 1;