Skip to content

Instantly share code, notes, and snippets.

@smls
Last active April 24, 2016 10:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save smls/0cd4988c8895f18d95df9cf8d9a9f640 to your computer and use it in GitHub Desktop.
Save smls/0cd4988c8895f18d95df9cf8d9a9f640 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl6
grammar Polynomial::Grammar {
rule TOP { <term>+ % <addsub> }
rule term { <part>+ % <muldiv> }
rule part { [<num> | <var>] <exp>? }
rule exp { '^' <num> }
token addsub { '+' | '-' }
token muldiv { '*' | '/' }
token var { <neg>? 'X' }
token num { <neg>? \d+ }
token neg { '-' }
}
class Term {
has Real $.factor;
has Int $.exponent;
}
class Polynomial {
has Term @.terms;
method from-string($string) {
Polynomial::Grammar.parse($string)
or die "Could not parse polynomial from string '$string'";
Polynomial.new: terms => do
for ('+', |$<addsub>) Z $<term> -> ($op, $term) {
my $factor = ($op eq '-' ?? -1 !! 1);
my $exponent = 0;
for ('*', |$term<muldiv>) Z $term<part> -> ($op, $part) {
my $exp = ($part<exp><num> // 1) * ($op eq '/' ?? -1 !! 1);
if $part<var> { $exponent += $exp;
$factor *= -1 if $part<var><neg> }
else { $factor *= $part<num> ** $exp }
}
Term.new(:$factor, :$exponent)
}
}
method derivative {
Polynomial.new: terms => @.terms.map: {
Term.new:
factor => .factor * .exponent || next,
exponent => .exponent - 1;
}
}
method gist {
join " + ", do for @.terms -> $term {
my $prefix = do given $term.factor {
when 1 { '' }
when -1 { '-' }
default { "$_*" }
}
do given $term.exponent {
when 0 { $term.factor }
when 1 { "{$prefix}X" }
default { "{$prefix}X^$_" }
}
}
}
}
#-----[ Usage ]-----
my $p = Polynomial.from-string("-X^2 + 1 / X * 4 - X^-4 - 3 * 5/6");
say $p; # -X^2 + 4*X^-1 + -X^-4 + -2.5
say $p.derivative; # -2*X + -4*X^-2 + 4*X^-5
#!/usr/bin/env perl6
# Slightly more golfed solution that does not clean up output in any way:
grammar Polynomial::Grammar {
rule TOP { <term>+ % <addsub> }
rule term { <part>+ % <muldiv> }
rule part { [<num> | <var>] <exp>? }
rule exp { '^' <num> }
token addsub { '+' | '-' }
token muldiv { '*' | '/' }
token var { <neg>? 'X' }
token num { <neg>? \d+ }
token neg { '-' }
}
class Polynomial::Actions::Derivative {
has $!out = '';
method TOP ($/) { say $!out }
method addsub ($/) { $!out ~= " $/ " }
method term ($/) {
my $coefficient = 1;
my $exponent = 0;
for ('*', |$<muldiv>) Z $<part> -> ($op, $part) {
my $exp = ($part<exp><num> // 1) * ($op eq '/' ?? -1 !! 1);
if $part<var> { $exponent += $exp;
$coefficient *= -1 if $part<var><neg> }
else { $coefficient *= $part<num> ** $exp }
}
$coefficient = $coefficient * $exponent;
$exponent = $exponent - 1;
$!out ~= "$coefficient*X^$exponent";
}
}
Polynomial::Grammar.parse:
"-X^2 + 1 / X * 4 - X^-4 - 3 * 5/6",
actions => Polynomial::Actions::Derivative.new;
# Output: -2*X^1 + -4*X^-2 - -4*X^-5 - 0*X^-1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment