Math-Yapp
view release on metacpan or search on metacpan
lib/Math/Yapp.pm view on Meta::CPAN
{ # degree, then
$self->{coeff}[$cur_degree] += $cur_coeff; # just add this one
}
else # No term of this degree yet
{ # This is new here
$self->{coeff}[$cur_degree] = $cur_coeff; # Set the coefficient now
}
} # End of for-loop to parse individual terms
# Bug fix (Too lazy to locate screw-up): Somehow I can get this far
# without a variable component. So just in case..
#
$self->{variable} = "X" if (!defined($self->{variable}));
return $self;
}
#
#------------------------------------------------------------------------------
# Yapp_plus - Function to implement the += operator
# Parameters:
# - (Implicit) [Reference to] my target object
# - The object to added to my target object. This may be:
# o Another Yapp polynomial object [reference]
# o A constant, either real or complex (a different, albeit smaller can
# of worms)
#
sub Yapp_plus
{
my ($self, $added) = @_; # Get relevant parameters. Swap is irrelevant
# Now, what is $added?
#
if (ref($added) eq $class_name) # If it is another polynomial
{
my $alc = 0; # Loop counter to step up added terms
my $new_degree = $self->{degree}; # Track degree in case the added
# polynomial has a higher degree
my @builder = @{$self->{coeff}}; # Copy coefficients into temporary list
for ($alc = 0; $alc <= $added->{degree}; $alc++) # For all terms of the
{ # added polynomial
if (defined($builder[$alc])) # If target has term of this degree
{ $builder[$alc] += $added->{coeff}[$alc]; } # Just add these terms
else { $builder[$alc] = $added->{coeff}[$alc]; } # Or copy this term
$new_degree = $alc if ($alc > $self->{degree}); # Maintain degree
}
# Temporary areas have been evaluated. Now plug these into target Yapp
#
$self->{degree} = $new_degree; # Carry over the augmented (?) degree
@{$self->{coeff}} = @builder; # and the augmented polynomial
} # And I have my return value
elsif ( ($added =~ m/^($coef_pat)$/)
|| (ref($added) eq $class_cplx) ) # Adding real or complex const
{
# As above: If the target term is defined, add the new term.
# Otherwise, set the target term to the given value
#
if (defined($self->{coeff}[0])) {$self->{coeff}[0] += $added;}
else {$self->{coeff}[0] = $added;}
} # (Just needed to augment the constant term)
else
{ die "Operator += requires a constant or a Yapp polynomial reference";}
# Didn't die - I have a good value to return
#
return ($self); # (Ought to return something)
}
#------------------------------------------------------------------------------
# Yapp_add() - Function (and overloaded + operator) to add two polynomials.
# Parameters:
# - (Implicit) The polynomial on the left side of the + (self)
# - The polynomial to be added. This may be:
# o (Implicit) [A reference to] another Yapp polynomial object
# o A constant, either real or complex (See Yapp_plus)
# - (Implicit) The "swapped" flag, largely irrelevant for the + operator
# Returns:
# A reference to a new Yapp polynomial
#
sub Yapp_add
{
my ($self, $adder, $swapped) = @_; #(swap is irrelelvant for add)
my $ryapp = Yapp($self); # Clone the original
$ryapp += $adder; # Let _plus() function handle details
return $ryapp; # Assume $ryapp will be auto-destroyed?
}
#
#------------------------------------------------------------------------------
# Yapp_minus(): Function (and overloaded -= operator) to subtract the passed
# polybnomial from the object polynomial in place. That is,
# it modifies the $self object
# - (Implicit) [Reference to] my target object
# - The object to added to my target object. This may be:
# o Another Yapp polynomial object [reference]
# o A constant, either real or complex
# Returns:
# - The same reference. But the target Yapp ahs been "deminished"
#
sub Yapp_minus
{
my ($self, $subtractor) = @_[0 .. 1];
if (ref($subtractor) eq $class_name) # Subtracting another polynimal
{ # just use the add method
my $temp_subt = $subtractor->Yapp_negate(); # Quickie way out: Negate and
# add, However I cant
my $temp_self = Yapp($self); # use -= on $sef. Dunno why
$temp_self += $temp_subt; # Add the negated Yapp
@{$self->{coeff}} = @{$temp_self->{coeff}}; # Restore subtracted
# coeffiecient array
}
else # Otherwise, just assume a constant
{ # be it real or complex.
# If our polynomial has no constant term, this is it, after negation.
#
$self->{coeff}[0] = (defined($self->{coeff}[0]))
? $self->{coeff}[0] - $subtractor
: - $subtractor ;
}
return $self;
}
lib/Math/Yapp.pm view on Meta::CPAN
# - (Implicit) The target object ($self)
# - The multiplier. This may be:
# o Another Yapp object (Happiest with this parameter type)
# o A real or complex constant
# Returns:
# The $self-same reference, but it has been "mutated" by the method.
#
sub Yapp_mult
{
my ($self, $multiplier) = @_;
my $aux_yapp; # I may have to create another Yapp
my $ylc; # Loop counter for stepping up coefficients
# Now what data type is the multiplier?
#
#Xif ( (ref($multiplier) eq "$class_cplx") # Complex number constant
#X || ( (ref(\$multiplier) eq "SCALAR") # or a scalar that happens
#X && ($multiplier =~ /^($coef_pat)$/))) # to be a real constant
#X Note: The above logic is good but for very low floating point numbers it
#X was failing to match the corefficient pattern. Hence, I relaxed the
#X matching requirement. -- Jacob
if ( (ref($multiplier) eq "$class_cplx") # Complex number constant
|| (ref(\$multiplier) eq "SCALAR" ) ) # or a scalar (Assume numeric)
{ # Just distribute multiplier
for ($ylc = 0; $ylc <= $self->{degree}; $ylc++)
{
$self->{coeff}[$ylc] *= $multiplier
if ($self->{coeff}[$ylc] != 0) ; # Don't bother multiplying 0
}
}
elsif (ref($multiplier) eq $class_name) # Multiplying by a polynomial
{
my @builder = (); # Build result area from scratch
my $new_degree = $self->{degree}
+ $multiplier->{degree}; # (Remember your 9th grade algebra?)
for ($ylc = 0; $ylc <= $self->{degree}; $ylc++)
{ # Outer loop multiplies one target term
for (my $mlc = 0; $mlc <= $multiplier->{degree}; $mlc++)
{ # Inner loop multiplies by one
# multiplier term
my $term_degree = $ylc + $mlc; # Degree of this target term
$builder[$term_degree] = 0.0 # Make sure there is a
if (! defined($builder[$term_degree])); # value in here to start
# Accumulate product term of that degree: Product of the terms whose
# exponents add up to the [eventual] exponent of this term
#
$builder[$term_degree] += $self->{coeff}[$ylc]
* $multiplier->{coeff}[$mlc] ;
} # End loop multiplying one target term by term from multiplier
} # End loop multiplying whole polynomials
# Done multiplication: Now put it back in place
#
$self->{degree} = $new_degree; # Copy back degree of multiplied target Yapp
@{$self->{coeff}} = @builder; # and copy back array where we carried
# out the multiplication.
} # All done multiplying Yapps; product is in place
else # No more permitted possibilities
{ die "Operator *= requires a constant or a Yapp polynomial reference";}
# Afterthought: I have found that when I multiply two poly's with conjugate
# complex constant terms, the result will include coefficients like like
# (30.00+0.00i); which is a real, of course, but doesn't look that way.
# Here's the fix:
#
realify(\@{$self->{coeff}});
return $self;
}
#
#------------------------------------------------------------------------------
# Yapp_times(): Method to implement the overloaded '*' operator
# Parameters:
# - (Implicit) The operand (usually the left) to the multiplicaton
# - [Reference] to the multiplier, which may be:
# o Another Yapp object (Happiest with this parameter type)
# o A real or complex constant
# - Swapped-operands flag, largely irrelevant for multiplication
# Returns:
# - [Reference to] a new Yapp polynomial that is the product of the first
# two parameters
#
sub Yapp_times
{
my ($self, $multiplier, $swapped) = @_;
my $ryapp; # The object to be returned
$ryapp = Yapp($self); # Make a copy
$ryapp *= $multiplier; # Carry out operation
return $ryapp; #(Wasnt't that simple?)
}
#
#------------------------------------------------------------------------------
# Yapp_power(): Method to implement exponentiation of polynomial by an
# integer power.
# Parameters:
# - (Implicit) The operand, a ref to the polynomial being multiplied by itself
# - The power, which must be an integer
# - Swapped-operands flag: grounds for immediate death
# Returns:
# - A [ref to a] Yapp polynomial that is the original raised to the
# indicated powert
#
sub Yapp_power
{
my ($self, $power, $swapped) = @_;
# Some validations:
#
die "You cannot raise a number to a polynomial power"
if ($swapped);
die "Power must be an integer"
if ($power != int($power));
# And now that that's been squared away: Get to work
#
my $ryapp = Yapp(1); # Start with a unit polynomial
while ($power-- > 0) # (Decrement after testing)
{
$ryapp *= $self; # Carry out the self-multiplication
( run in 2.094 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )