Math-NumSeq
view release on metacpan or search on metacpan
lib/Math/NumSeq/Expression.pm view on Meta::CPAN
# Workaround: Something fishy in Safe 2.29 and perl 5.14.2 meant that
# after a Safe->new(), any subsequently loaded code dragging in %- named
# captures fails to load Tie::Hash::NamedCapture. Load it now, if it
# exists. This affects Language::Expr which uses Regexp::Grammars which
# has $-{'foo'}.
#
# Safe 2.30 has it fixed, so can skip there, unless or until want to
# depend outright on that version
# http://perl5.git.perl.org/perl.git/commitdiff/ad084f51cd17539ef55b510228156cd4f83c9729
#
eval { Safe->VERSION(2.30); 1 }
or eval { require Tie::Hash::NamedCapture };
require Safe;
my $safe = Safe->new;
$safe->permit('print',
':base_math', # sqrt(), rand(), etc
);
if (eval { require List::Util; 1 }) {
$safe->share_from('List::Util', [ 'min','max' ]);
}
require POSIX;
$safe->share_from('POSIX', [ 'floor','ceil' ]);
require Math::Trig;
$safe->share_from('Math::Trig', [qw(tan
asin acos atan
csc cosec sec cot cotan
acsc acosec asec acot acotan
sinh cosh tanh
csch cosech sech coth cotanh
asinh acosh atanh
acsch acosech asech acoth acotanh
)]);
require Math::Libm;
$safe->share_from('Math::Libm', [qw(cbrt
erf
erfc
expm1
hypot
j0
j1
jn
lgamma_r
log10
log1p
pow
rint
y0
y1
yn)]);
my $pi = Math::Libm::M_PI();
my $e = Math::Libm::M_E();
$subr = $safe->reval("\n#line ".(__LINE__+2)." \"".__FILE__."\"\n"
. <<"HERE");
my \$pi = $pi;
my \$e = $e;
my \$phi = (1+sqrt(5))/2;
my \$gam = 0.5772156649015328606065120;
my \$i;
sub i () { return \$i }
sub {
\$i = \$_[0];
return do { $expression }
}
HERE
### $subr
if (! $subr) {
croak "Invalid or unsafe expression: $@\n";
}
} elsif ($evaluator eq 'MS') {
require Math::Symbolic;
my $tree = Math::Symbolic->parse_from_string($expression);
if (! defined $tree) {
croak "Cannot parse MS expression: $expression";
}
# simplify wrong result on x+(-5)*y before 0.605 ...
if (eval { $tree->VERSION(0.605); 1 }) {
$tree = $tree->simplify;
}
my @vars = $tree->signature;
if (@vars > 1) {
croak "More than one variable in MS expression: $expression\n(simplified to $tree)";
}
### code: $tree->to_code
($subr) = $tree->to_sub(\@vars);
### $subr
} elsif ($evaluator eq 'MEE') {
require Math::Expression::Evaluator;
my $me = Math::Expression::Evaluator->new;
$me->set_function('min', \&List::Util::min);
$me->set_function('max', \&List::Util::max);
$me->parse('pi='.Math::Libm::M_PI()
.'; e='.Math::Libm::M_E()
.'; phi=(1+sqrt(5))/2'
.'; gam=0.5772156649015328606065120');
$me->val;
eval { $me->parse ($expression); 1 }
or croak "Cannot parse MEE expression: $expression\n$@";
# my @vars = $me->variables;
my @vars = _me_free_variables($me);
if (@vars > 1) {
croak "More than one variable in MEE expression: $expression";
}
my $hashsub = $me->compiled;
### $hashsub
### _ast_to_perl: $me->_ast_to_perl($me->{ast})
my $v = $vars[0];
my %vars;
if (@vars) {
$subr = sub {
$vars{$v} = $_[0];
return &$hashsub(\%vars);
( run in 0.663 second using v1.01-cache-2.11-cpan-524268b4103 )