Last active
April 24, 2016 10:00
-
-
Save smls/0cd4988c8895f18d95df9cf8d9a9f640 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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