\r
*/\r
\r
+/**\r
+ * This class was heavily modified in order to get usefull spreadsheet emulation ;-)\r
+ * skodak\r
+ * \r
+ */\r
+\r
class EvalMath {\r
\r
var $suppress_errors = false;\r
\r
var $v = array(); // variables (and constants)\r
var $f = array(); // user-defined functions\r
- var $vb = array('e', 'pi'); // constants\r
+ var $vb = array(); // constants\r
var $fb = array( // built-in functions\r
'sin','sinh','arcsin','asin','arcsinh','asinh',\r
'cos','cosh','arccos','acos','arccosh','acosh',\r
'tan','tanh','arctan','atan','arctanh','atanh',\r
- 'sqrt','abs','ln','log');\r
+ 'sqrt','abs','ln','log','exp');\r
\r
var $fc = array( // calc functions emulation\r
- 'sum'=>array(-1), 'pi'=>array(0), 'power'=>array(2), 'round'=>array(2,1), 'average'=>array(-1));\r
+ 'average'=>array(-1), 'max'=>array(-1), 'min'=>array(-1),\r
+ 'mod'=>array(2), 'pi'=>array(0), 'power'=>array(2),\r
+ 'round'=>array(1, 2), 'sum'=>array(-1));\r
\r
function EvalMath() {\r
}\r
}\r
\r
function vars() {\r
- $output = $this->v;\r
- unset($output['pi']);\r
- unset($output['e']);\r
- return $output;\r
+ return $this->v;\r
}\r
\r
function funcs() {\r
// spreadsheed functions emulation\r
// watch out for reversed args!!\r
class EvalMathCalcEmul {\r
+\r
function average($args) {\r
return (EvalMathCalcEmul::sum($args)/count($args));\r
}\r
\r
+ function max($args) {\r
+ $res = array_pop($args);\r
+ foreach($args as $a) {\r
+ if ($res < $a) {\r
+ $res = $a;\r
+ }\r
+ }\r
+ return $res;\r
+ }\r
+\r
+ function min($args) {\r
+ $res = array_pop($args);\r
+ foreach($args as $a) {\r
+ if ($res > $a) {\r
+ $res = $a;\r
+ }\r
+ }\r
+ return $res;\r
+ }\r
+\r
+ function mod($args) {\r
+ return $args[1] % $args[0];\r
+ }\r
+\r
function pi($args) {\r
return pi();\r
}\r
\r
function power($args) {\r
- return $args[0]^$args[0];\r
+ return $args[1]^$args[0];\r
}\r
\r
function round($args) {\r
function sum($args) {\r
$res = 0;\r
foreach($args as $a) {\r
- $res += $a; \r
+ $res += $a;\r
}\r
return $res;\r
}\r
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;
}
}
<?php
-/* $Id$ */
-
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
}
require_once($CFG->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');
}
/**
- * 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));
}
/**
- * 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');
}
}