From 7458bee224f622a40ad701c77feec163e7528eff Mon Sep 17 00:00:00 2001 From: skodak Date: Sat, 26 May 2007 12:59:13 +0000 Subject: [PATCH] MDL-9643 some more polishing --- lib/evalmath/evalmath.class.php | 48 +++++++++++++++++++----- lib/mathslib.php | 65 ++++++++++++++++++++++++--------- lib/simpletest/testmathslib.php | 36 +++++++++++++----- 3 files changed, 113 insertions(+), 36 deletions(-) diff --git a/lib/evalmath/evalmath.class.php b/lib/evalmath/evalmath.class.php index 2270d626e0..37a419715c 100644 --- a/lib/evalmath/evalmath.class.php +++ b/lib/evalmath/evalmath.class.php @@ -86,6 +86,12 @@ LICENSE */ +/** + * This class was heavily modified in order to get usefull spreadsheet emulation ;-) + * skodak + * + */ + class EvalMath { var $suppress_errors = false; @@ -93,15 +99,17 @@ class EvalMath { var $v = array(); // variables (and constants) var $f = array(); // user-defined functions - var $vb = array('e', 'pi'); // constants + var $vb = array(); // constants var $fb = array( // built-in functions 'sin','sinh','arcsin','asin','arcsinh','asinh', 'cos','cosh','arccos','acos','arccosh','acosh', 'tan','tanh','arctan','atan','arctanh','atanh', - 'sqrt','abs','ln','log'); + 'sqrt','abs','ln','log','exp'); var $fc = array( // calc functions emulation - 'sum'=>array(-1), 'pi'=>array(0), 'power'=>array(2), 'round'=>array(2,1), 'average'=>array(-1)); + 'average'=>array(-1), 'max'=>array(-1), 'min'=>array(-1), + 'mod'=>array(2), 'pi'=>array(0), 'power'=>array(2), + 'round'=>array(1, 2), 'sum'=>array(-1)); function EvalMath() { } @@ -151,10 +159,7 @@ class EvalMath { } function vars() { - $output = $this->v; - unset($output['pi']); - unset($output['e']); - return $output; + return $this->v; } function funcs() { @@ -424,16 +429,41 @@ class EvalMathStack { // spreadsheed functions emulation // watch out for reversed args!! class EvalMathCalcEmul { + function average($args) { return (EvalMathCalcEmul::sum($args)/count($args)); } + function max($args) { + $res = array_pop($args); + foreach($args as $a) { + if ($res < $a) { + $res = $a; + } + } + return $res; + } + + function min($args) { + $res = array_pop($args); + foreach($args as $a) { + if ($res > $a) { + $res = $a; + } + } + return $res; + } + + function mod($args) { + return $args[1] % $args[0]; + } + function pi($args) { return pi(); } function power($args) { - return $args[0]^$args[0]; + return $args[1]^$args[0]; } function round($args) { @@ -447,7 +477,7 @@ class EvalMathCalcEmul { function sum($args) { $res = 0; foreach($args as $a) { - $res += $a; + $res += $a; } return $res; } diff --git a/lib/mathslib.php b/lib/mathslib.php index fa4f7abfd0..3eb9cb41a4 100644 --- a/lib/mathslib.php +++ b/lib/mathslib.php @@ -2,55 +2,86 @@ require_once $CFG->dirroot.'/lib/evalmath/evalmath.class.php'; +/** + * This class abstracts evaluation of spreadsheet formulas. + * See unit tests in lib/simpletest/testmathslib.php for sample usage. + * + * @author Petr Skoda (skodak) + * @license http://www.gnu.org/copyleft/gpl.html GNU Public License + */ class calc_formula { - var $em; - var $nfx = false; - var $error = false; + // private properties + var $_em; + var $_nfx = false; // postfix expression + var $_error = false; // last error + /** + * Constructor for spreadsheet formula with optional parameters + * + * @param string $formula with leading = + * @param array $params associative array of parameters used in formula. All parameter names must be lowercase! + */ function calc_formula($formula, $params=false) { - $this->em = new EvalMath(); - $this->em->suppress_errors = true; + $this->_em = new EvalMath(); + $this->_em->suppress_errors = true; if (strpos($formula, '=') !== 0) { - $this->error = "missing '='"; + $this->_error = "missing '='"; return; } $formula = substr($formula, 1); if (strpos($formula, '=') !== false) { - $this->error = "too many '='"; + $this->_error = "too many '='"; return; } - $this->nfx = $this->em->nfx($formula); - if ($this->nfx == false) { - $this->error = $this->em->last_error; + $this->_nfx = $this->_em->nfx($formula); + if ($this->_nfx == false) { + $this->_error = $this->_em->last_error; return; } if ($params != false) { - $this->em->v = $params; + $this->set_params($params); } } + /** + * Raplace parameters used in calculation + * + * @param array $params associative array of parameters used in formula. All parameter names must be lowercase! + */ function set_params($params) { - $this->em->v = $params; + $this->_em->v = $params; } + /** + * Evaluate formula + * + * @return mixed number if ok, false if error + */ function evaluate() { - if ($this->nfx == false) { + if ($this->_nfx == false) { return false; } - $res = $this->em->pfx($this->nfx); + $res = $this->_em->pfx($this->_nfx); if ($res === false) { - $this->error = $this->em->last_error; + $this->_error = $this->_em->last_error; return false; } else { - $this->error = false; + $this->_error = false; return $res; } } + /** + * Get last error. + * + * TODO: localize the strings + * + * @return mixed string with last error description or false if ok + */ function get_error() { - return $this->error; + return $this->_error; } } diff --git a/lib/simpletest/testmathslib.php b/lib/simpletest/testmathslib.php index 783fdd3c28..4f6d02e16b 100755 --- a/lib/simpletest/testmathslib.php +++ b/lib/simpletest/testmathslib.php @@ -1,7 +1,5 @@ libdir . '/simpletestlib.php'); require_once($CFG->libdir . '/mathslib.php'); +/** + * Unit tests of mathslib wrapper and underlying EvalMath library. + * + * @author Petr Skoda (skodak) + * @version $Id$ + */ class mathsslib_test extends UnitTestCase { /** - * Tests the basic formula execition + * Tests the basic formula evaluation */ function test__basic() { $formula = new calc_formula('=1+2'); @@ -31,7 +35,19 @@ class mathsslib_test extends UnitTestCase { } /** - * Tests the formula params + * Tests the changed params + */ + function test__changing_params() { + $formula = new calc_formula('=a+b+c', array('a'=>10,'b'=>20,'c'=>30)); + $res = $formula->evaluate(); + $this->assertEqual($res, 60, '10+20+30 is: %s'); + $formula->set_params(array('a'=>1,'b'=>2,'c'=>3)); + $res = $formula->evaluate(); + $this->assertEqual($res, 6, 'changed params 1+2+3 is: %s'); + } + + /** + * Tests the spreadsheet emulation function in formula */ function test__calc_function() { $formula = new calc_formula('=sum(a,b,c)', array('a'=>10,'b'=>20,'c'=>30)); @@ -40,15 +56,15 @@ class mathsslib_test extends UnitTestCase { } /** - * Tests the formula changed params + * Tests the min and max functions */ - function test__changing_params() { - $formula = new calc_formula('=a+b+c', array('a'=>10,'b'=>20,'c'=>30)); + function test__minmax_function() { + $formula = new calc_formula('=min(a,b,c)', array('a'=>10,'b'=>20,'c'=>30)); $res = $formula->evaluate(); - $this->assertEqual($res, 60, '10+20+30 is: %s'); - $formula->set_params(array('a'=>1,'b'=>2,'c'=>3)); + $this->assertEqual($res, 10, 'minimum is: %s'); + $formula = new calc_formula('=max(a,b,c)', array('a'=>10,'b'=>20,'c'=>30)); $res = $formula->evaluate(); - $this->assertEqual($res, 6, 'changed params - 1+2+3 is: %s'); + $this->assertEqual($res, 30, 'maximum is: %s'); } } -- 2.39.5