Permalink
Browse files

[cpan] MEE Add examples, many minor changes

git-svn-id: svn+ssh://faui2k3.org/var/lib/svn/moritz/cpan/Math-Expression-Evaluator@714 addfbb1e-f4f9-0310-b6f0-bccd0f9b8dc6
  • Loading branch information...
1 parent f394296 commit 3a00f6821f8600acba9a5ea2d12edf29eab9e0f7 moritz committed Jul 13, 2008
View
@@ -10,9 +10,9 @@ my $build = Module::Build->new(
module_name => 'Math::Expression::Evaluator',
dist_author => 'Moritz Lenz',
dist_abstract => undef,
- dist_version => '0.0.6',
+ dist_version => '0.1.1',
requires => {
- 'perl' => '5.6.1',
+ 'perl' => '5.006001',
'Carp' => 0,
'Math::Trig' => 0,
'Data::Dumper' => 0,
View
11 Changes
@@ -1,5 +1,16 @@
Revision History for Perl module Math::Expression::Evaluator
+0.1.1 Wed Jun 18 22:28:48 CEST 2008
+- require perl version 5.006001, not 5.6.1. Perl 5.5something doesn't
+ understand the latter.
+
+0.1.0 Sun Jun 8 12:30:06 CEST 2008
+- ast_size is now a public method
+- added two examples
+- increased submajor version number to 1 to reflect increasing maturity
+- don't hide modules from PAUSE indexer, cpants complains about missing
+ dependencies otherwie
+
0.0.6 Thu Apr 3 09:09:37 CEST 2008
- added modulo operator %
- documented variable handling of compiled functions
View
@@ -1,5 +1,8 @@
+benchmark.pl
Build.PL
Changes
+examples/evalbot.pl
+examples/simple.pl
lib/Math/Expression/Evaluator.pm
lib/Math/Expression/Evaluator/Lexer.pm
lib/Math/Expression/Evaluator/Optimizer.pm
@@ -12,14 +15,18 @@ README
t/00-use.t
t/01-pod.t
t/02-pod-coverage.t
+t/03-basic-usage.t
t/builtins.t
t/exec-fails.t
t/infix.t
+t/lex.t
t/multiple-expressions.t
t/null.t
t/numbers.t
+t/optimize-effect.t
t/optimize.t
t/parsefails.t
t/precedence.t
t/prefix.t
+t/variable_list.t
t/variables.t
View
@@ -1,17 +1,30 @@
---
name: Math-Expression-Evaluator
-version: 0.0.6
+version: 0.1.1
author:
- Moritz Lenz
-abstract: ~
+abstract: 'parses, compiles and evaluates mathematic expressions'
license: perl
+resources:
+ license: http://dev.perl.org/licenses/
requires:
Carp: 0
Data::Dumper: 0
Math::Trig: 0
- perl: 5.6.1
+ perl: 5.006001
provides:
Math::Expression::Evaluator:
file: lib/Math/Expression/Evaluator.pm
- version: 0.0.6
-generated_by: Module::Build version 0.26
+ version: 0.1.1
+ Math::Expression::Evaluator::Lexer:
+ file: lib/Math/Expression/Evaluator/Lexer.pm
+ Math::Expression::Evaluator::Optimizer:
+ file: lib/Math/Expression/Evaluator/Optimizer.pm
+ Math::Expression::Evaluator::Parser:
+ file: lib/Math/Expression/Evaluator/Parser.pm
+ Math::Expression::Evaluator::Util:
+ file: lib/Math/Expression/Evaluator/Util.pm
+generated_by: Module::Build version 0.280801
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.2.html
+ version: 1.2
View
@@ -1,15 +1,17 @@
-# Note: this file was auto-generated by Module::Build::Compat version 0.03
+# Note: this file was auto-generated by Module::Build::Compat version 0.2808_01
+require 5.006001;
use ExtUtils::MakeMaker;
WriteMakefile
(
+ 'PL_FILES' => {},
+ 'INSTALLDIRS' => 'site',
'NAME' => 'Math::Expression::Evaluator',
- 'VERSION' => '0.0.6',
+ 'EXE_FILES' => [],
+ 'VERSION_FROM' => 'lib/Math/Expression/Evaluator.pm',
'PREREQ_PM' => {
- 'Carp' => '0',
- 'Data::Dumper' => '0',
- 'Math::Trig' => '0'
- },
- 'INSTALLDIRS' => 'site',
- 'PL_FILES' => {}
+ 'Math::Trig' => 0,
+ 'Data::Dumper' => 0,
+ 'Carp' => 0
+ }
)
;
View
184 README
@@ -0,0 +1,184 @@
+NAME
+ Math::Expression::Evaluator - parses, compiles and evaluates mathematic
+ expressions
+
+SYNOPSIS
+ use Math::Expression::Evaluator;
+ my $m = new Math::Expression::Evaluator;
+
+ print $m->parse("a = 12; a*3")->val(), "\n";
+ # prints 36
+ print $m->parse("2^(a/3)")->val(), "\n";
+ # prints 8 (ie 2**3)
+ print $m->parse("a / b")->val({ b => 6 }), "\n";
+ # prints 36
+ print $m->parse("log2(16)")->val(), "\n";
+ # prints 4
+
+ # if you care about speed
+ my $func = $m->parse('2 + (4 * b)')->compiled;
+ for (0 .. 100){
+ print $func->({b => $_}), "\n";
+ }
+
+DESCRIPTION
+ Math::Expression::Evaluator is a parser, compiler and interpreter for
+ mathematical expressions. It can handle normal arithmetics (includings
+ powers ^), builtin functions like sin() and variables.
+
+ Multiplication "*", division "/" and modulo "%" have the same
+ precedence, and are evaluated left to right. The modulo operation
+ follows the standard perl semantics, that is is the arguments are castet
+ to integer before preforming the modulo operation.
+
+ Multiple exressions can be seperated by whitespaces or by semicolons
+ ';'. In case of multiple expressions the value of the last expression is
+ returned.
+
+ Variables can be assigned with a single '=' sign, their name has to
+ start with a alphabetic character or underscore "[a-zA-Z_]", and may
+ contain alphabetic characters, digits and underscores.
+
+ Values for variables can also be provided as a hash ref as a parameter
+ to val(). In case of collision the explicitly provided value is used:
+
+ $m->parse("a = 2; a")->val({a => 1});
+
+ will return 1, not 2.
+
+ The following builtin functions are supported atm:
+
+ * trignometric functions: sin, cos, tan
+
+ * inverse trigonomic functions: asin, acos, atan
+
+ * Square root: sqrt
+
+ * exponentials: exp, sinh, cosh
+
+ * logarithms: log, log2, log10
+
+ * constants: pi() (you need the parenthesis to distinguish it from the
+ variable pi)
+
+ * rounding: ceil(), floor()
+
+ * other: theta (theta(x) = 1 for x > 0, theta(x) = 0 for x < 0)
+
+METHODS
+ new
+ generates a new MathExpr object. accepts an optional argument, a hash
+ ref that contains configurations. If this hash sets force_semicolon to
+ true, expressions have to be separated by a semicolon ';'.
+
+ parse
+ Takes a string as argument, and generates an Abstract Syntax Tree(AST)
+ that is stored internally.
+
+ Returns a reference to the object, so that method calls can be
+ chained:
+
+ print MathExpr->new->parse("1+2")->val;
+
+ Parse failures cause this method to die with a stack trace.
+
+ compiled
+ Returns an anonymous function that is a compiled version of the
+ current expression. It is much faster to execute than the other
+ methods, but its error messages aren't as informative (instead of
+ complaining about a non-existing variable it dies with "Use of
+ uninitialized value in...").
+
+ Note that variables are not persistent between calls to compiled
+ functions (and it wouldn't make sense anyway, because such a function
+ corresponds always to exactly one expression, not many as a MEE
+ object).
+
+ Variables that were stored at the time when "compiled()" is called are
+ availble in the compiled function, though.
+
+ val
+ Executes the AST generated by parse(), and returns the number that the
+ expression is evaluated to. It accepts an optional hash reference that
+ contain values for variables:
+
+ my $m = new MathExpr;
+ $m->parse("(x - 1) / (x + 1)");
+ foreach (0 .. 10) {
+ print $_, "\t", $m->val({x => $_}), "\n";
+ }
+
+ optimize
+ Optimizes the internal AST, so that subsequent calls to "val()" will
+ be a bit faster. See "Math::Expression::Evaluator::Optimizer" for
+ performance considerations and informations on the implemented
+ optimizations.
+
+ But note that a call to "optimize()" only pays off if you call "val()"
+ multiple times.
+
+ variables
+ "variables()" returns a list of variables that are used in the
+ expression.
+
+ ast_size
+ "ast_size" returns an integer which gives a crude measure of the
+ logical size of the expression. Note that this value isn't guarantueed
+ to be stable across multiple versions of this module. It is mainly
+ intended for testing.
+
+SPEED
+ MEE isn't as fast as perl, because it is built on top of perl.
+
+ If you execute an expression multiple times, it pays off to either
+ optimize it first, or (even better) compile it to a pure perl function.
+
+ Rate no_optimize optimize opt_compiled compiled
+ no_optimize 83.9/s -- -44% -82% -83%
+ optimize 150/s 78% -- -68% -69%
+ opt_compiled 472/s 463% 215% -- -4%
+ compiled 490/s 485% 227% 4% --
+
+ This shows the time for 200 evaluations of "2+a+5+(3+4)" (with MEE
+ 0.0.5). As you can see, the non-optimized version is painfully slow,
+ optimization nearly doubles the execution speed. The compiled and the
+ optimized-and-then-compiled versions are both much faster.
+
+ With this example expression the optimization prior to compilation pays
+ off if you evaluate it more than 1000 times. But even if you call it
+ "10**5" times the optimized and compiled version is only 3% faster than
+ the directly compiled one (mostly due to perl's overhead for method
+ calls).
+
+ So to summarize you should compile your expresions, and if you have
+ really many iterations it might pay off to optimize it first (or to
+ write your program in C instead ;-).
+
+BUGS AND LIMITATIONS
+ * Modulo operator produces an unnecessary big AST, making it
+ relatively slow
+
+INTERNALS
+ The AST can be accessed as "$obj-"{ast}>. Its structure is described in
+ Math::Expression::Evaluator::Parser (or you can use Data::Dumper to
+ figure it out for yourself).
+
+SEE ALSO
+ Math::Expression also evaluates mathematical expressions, but also
+ handles string operations.
+
+ If you want to do symbolic (aka algebraic) transformations,
+ Math::Symbolic will fit your needs.
+
+LICENSE
+ This module is free software. You may use, redistribute and modify it
+ under the same terms as perl itself.
+
+AUTHOR
+ Moritz Lenz, <http://moritz.faui2k3.org/>, moritz@faui2k3.org
+
+DEVELOPMENT
+ You can obtain the latest development version via subversion:
+
+ svn co https://faui2k3.org/svn/moritz/cpan/Math-Expression-Evaluator/
+
View
@@ -0,0 +1,68 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+
+# Suppose you want to write an all-purpose IRC bot. One of its cool features
+# is that if somebody writes down a mathematic expression, your bot will
+# print the results.
+#
+# now since you're a very sociable hacker you want to reduce line noise as
+# much as possible, which means that your bot won't print error messages if
+# something went wrong, and if somebody writes simply a number, your bot
+# doesn't just echo it - remember, a number is also a valid expression.
+
+# the IRC bot part can be done very simply with Bot::BasicBot. Here I just
+# present the math logic
+
+# for finding the modules even if not installed - not needed if you install
+# the module properly (recommended ;-)).
+use lib '../lib/';
+use lib 'lib';
+
+use Math::Expression::Evaluator;
+my $m = Math::Expression::Evaluator->new();
+
+sub my_math_eval {
+ my $str = shift;
+
+ # catch any errors:
+ my $r = eval {
+ $m->parse($str);
+ # parse will throw an exception if something went wrong.
+ # if we are here, it means that the expression was parsed fine
+
+ # now check if the expression worth evaluating at all:
+ return if $m->ast_size < 2;
+
+ # and finally do the work:
+ return $m->val();
+ };
+ if ($@){
+ # an error occured - return undef:
+ return;
+ } else {
+ return $r;
+ }
+}
+
+# now test our sub:
+
+my @inputs = (
+ 'some random test',
+ '234',
+ '1.234e23',
+ '1/0',
+ '2+3',
+ '2^20',
+ '2-2',
+);
+
+for (@inputs) {
+ my $r = my_math_eval($_);
+ if (defined $r){
+ print "Input: <$_> produced $r\n";
+ } else {
+ print "Input <$_> produced no output\n";
+ }
+}
Oops, something went wrong.

0 comments on commit 3a00f68

Please sign in to comment.