Source for file RPN.php
Documentation is available at RPN.php
* Change Expression To RPN (Reverse Polish Notation), Evaluate RPN Expression
* $expression = "(2^3)+sin(30)-(!4)+(3/4)";
* echo $rpn->calculate($expression,'deg',false);
* @author Maciej Szczytowski <admin@e-rower.pl>
* Array with input expression
var $_input_array = array ();
* Array with output expression in RPN
* Angle's unit: rad - true, deg - false
* Array of operators whit priority and math function
* operator => (name, priority, number of arguments, function)
var $_operation = array (
'(' => array ('left bracket', 0 ),
')' => array ('right bracket', 1 ),
'+' => array ('sum', 1 , 2 , '_sum'),
'-' => array ('difference', 1 , 2 , '_difference'),
'*' => array ('multiplication', 2 , 2 , '_multiplication'),
'/' => array ('division', 2 , 2 , '_division'),
'r' => array ('root', 3 , 2 , '_root'),
'^' => array ('power', 3 , 2 , '_power'),
'sin' => array ('sine', 3 , 1 , '_sin'),
'cos' => array ('cosine', 3 , 1 , '_cos'),
'tan' => array ('tangent', 3 , 1 , '_tan'),
'asin' => array ('asine', 3 , 1 , '_asin'),
'acos' => array ('acosine', 3 , 1 , '_acos'),
'atan' => array ('atangent', 3 , 1 , '_atan'),
'sqrt' => array ('square root', 3 , 1 , '_sqrt'),
'exp' => array ('power of e', 3 , 1 , '_exp'),
'log' => array ('logarithm', 3 , 1 , '_log'),
'ln' => array ('natural logarithm', 3 , 1 , '_ln'),
'E' => array ('power of 10', 3 , 1 , '_E'),
'abs' => array ('absolute value', 3 , 1 , '_abs'),
'!' => array ('factorial', 3 , 1 , '_factorial'),
'pi' => array ('value of pi', 4 , 0 , '_const_pi'),
'e' => array ('value of e', 4 , 0 , '_const_e'),
'mod' => array ('modulo', 3 , 2 , '_mod'),
'div' => array ('integer division', 3 , 2 , '_div'),
* @return object PEAR error
function _raiseError ($error) {
return PEAR ::raiseError ($error);
* Return a operator's array
* @return array Array with operator's name, priority, arguments, function's name and syntax
while (list ($key, $val) = each($this->_operation)) {
$syntax = 'A ' . $key . ' B';
'arguments' => $arguments,
* @param string $operator New operator
* @param string $function Function name
* @param integer $priority New operator's priority
* @param integer $no_of_arg Number of function's arguments
* @param string $text New operator's description
function addOperator ($operator, $function_name, $priority = 3 , $no_of_arg = 0 , $text = '') {
if(preg_match("/^([\W\w]+)\:\:([\W\w]+)$/",$function_name,$match)) {
'type' => 'userFunction',
'function' => $function_name
$this->_operation[$operator] = array ($text, $priority, $no_of_arg, $function);
* Calculate the $input expression
* @param mixed $input Infix expression string or RPN expression string
* @param string $angle Angle's unit - 'rad' or 'deg'
* @param boolean $is_rpn True if $input is RPN expression or false if $input is infix expression
* @return mixed Value of $input expression or a PEAR error
function calculate($input = '', $angle = 'rad', $is_rpn = true ) {
$this->_angle = (boolean) ($angle == 'rad');
$this->_error = $this->_raiseError ('Empty input expression');
$this->_stringToArray ();
if($this->_error <> null ) return $this->_error;
if($this->_error <> null ) return $this->_error;
$this->_input_array = explode(' ',$input);
$this->_output = explode(' ',$input);
if($this->_error <> null ) return $this->_error;
* Calculate the $input expression (alias of calculate())
* @param mixed $input Infix expression string or RPN expression array
* @param string $angle Angle's unit - 'rad' or 'deg'
* @param boolean $is_rpn True if $input is RPN expression or false if $input is infix expression
* @return mixed Value of $input expression or a PEAR error
function evaluate($input = '', $angle = 'rad', $is_rpn = false ) {
return $this-> calculate($input, $angle, $is_rpn);
* @return array Input array
return $this->_input_array;
* @return array RPN array
* Return a counting time in second
* @return float Counting time in seconds
* Check that $key is a key of $array (conformity to php<4.1.0)
* @param integer $type 0 - return true if $key is $array's key, 1 - return true if $key is $array's key and there isn't any occurrence of $key in another $array's key
* @return boolean true when $key is a key of $array, or false
function _keyExists ($key,$array,$type) {
while (list ($keys_key, $keys_val) = each($keys)) {
if(($count==1 ) && in_array($key,$keys)) return true;
* Check that $value is nan (conformity to php<4.2.0)
* @param float $value checking value
* @return boolean true when $value is nan, or false
function _isNan ($value) {
if((substr($value,-3 ) == 'IND') || (substr($value,-3 ) == 'NAN')) return true;
* Check that $value is infinite (conformity to php<4.2.0)
* @param float $value checking value
* @return boolean true when $value is infinite, or false
function _isInfinite ($value) {
if(substr($value,-3 ) == 'INF') return true;
* Change input expression into array
* @return array Input expression changed into array
function _stringToArray () {
for($i = 0; $i < strlen($this->_input); $i++ ) {
if ($this->_input[$i] == ' ') {
if ($temp_operator != null ) {
if ($temp_value != null ) {
} elseif (($temp_value == null ) && $temp_operator != ')' && (!array_key_exists($temp_operator,$this->_operation) || !array_key_exists(2 ,$this->_operation[$temp_operator]) || $this->_operation[$temp_operator][2 ]>0 ) && ($this->_input[$i] == '-')) {
if ($temp_operator != null ) {
} elseif ((is_numeric($this->_input[$i])) || ($this->_input[$i] == '.')) {
if ($temp_operator != null ) {
$temp_value .= $this->_input[$i];
if ($this->_keyExists ($temp_operator, $this->_operation, 1 )) {
if ($temp_value != null ) {
$temp_operator .= $this->_input[$i];
if ($temp_operator != null && $temp_operator != ' ') {
} elseif ($temp_value != null && $temp_value != ' ') {
return $this->_input_array;
* Check input array and return correct array or a PEAR Error
* @return object Null or a PEAR Error
if (!count($this->_input_array)) {
$this->_input_array = null;
$this->_error = $this->_raiseError ('Undefined input array');
for($i = 0; $i < count($this->_input_array); $i++ ) if ($this->_input_array[$i] == '(') $bracket++;
for($i = 0; $i < count($this->_input_array); $i++ ) if ($this->_input_array[$i] == ')') $bracket--;
$this->_input_array = null;
$this->_error = $this->_raiseError ('Syntax error');
for($i = 0; $i < count($this->_input_array); $i++ ) {
if ((!is_numeric($this->_input_array[$i])) && (!$this->_keyExists ($this->_input_array[$i], $this->_operation, 0 ))) {
$error_operator = $this->_input_array[$i];
$this->_input_array = null;
$this->_error = $this->_raiseError ('Undefined operator \''. $error_operator. '\'');
* Add value to the end of stack
* @param string $value Value to add into stack
function _stackAdd ($value) {
* Delete and return value from the end of stack
* @return string Value deleted from stack
function _stackDelete () {
* Return priority of value
* @param string $value Value to get priority
* @return integer Priority
function _priority ($value) {
return $this->_operation[$value][1 ];
* Return priority of value from the end of stack
* @return integer Priority of operator from stack's top
function _stackPriority () {
$value = $this->_stackDelete ();
$this->_stackAdd ($value);
return $this->_priority ($value);
* Return true whene the stack is empty
* @return boolean Stack is empty (true) or not (false)
if (count($this->_stack)) {
* Add value into output array
* @param string $value Value to add into output array
function _outputAdd ($value) {
* Change input array into RPN array
* @return array Array with RPN expression
if ($this->_error <> null ) {
$this->_output = array ();
for($i = 0; $i < count($this->_input_array); $i++ ) {
$temp = $this->_input_array[$i];
$this->_outputAdd ($temp);
while (!$this->_stackEmpty () && ($this->_stackPriority () >= 1 )) {
$this->_outputAdd ($this->_stackDelete ());
if (!$this->_stackEmpty ()) {
} elseif (($this->_stackEmpty ()) || (($this->_priority ($temp) > $this->_stackPriority ()))) {
$this-> _stackAdd ($temp);
while (!$this->_stackEmpty () && ($this->_priority ($temp) <= $this->_stackPriority ())) {
$this->_outputAdd ($this->_stackDelete ());
while (!$this->_stackEmpty ()) {
$this->_outputAdd ($this->_stackDelete ());
* Return position of the first operator in array
* @param array $array Temporary array
* @return integer Position of the first operator
function _nextOperator ($array) {
if ($pos >= count($array)) {
* Delete from array operator [posision $pos] and its argument and insert new value
* @param array $temp Temporary array
* @param integer $pos Position of the last operator
* @param integer $arg Number of last operator's arguments
* @param float $result Last operation result
* @return array New temporary array
function _refresh ($temp, $pos, $arg, $result) {
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _sum ($temp, $pos) {
return $temp[$pos-2 ]+ $temp[$pos-1 ];
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _difference ($temp, $pos) {
return $temp[$pos-2 ]- $temp[$pos-1 ];
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _multiplication ($temp, $pos) {
return $temp[$pos-2 ]* $temp[$pos-1 ];
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _division ($temp, $pos) {
$this->_error = $this->_raiseError ('Division by 0');
return $temp[$pos-2 ]/ $temp[$pos-1 ];
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _root ($temp, $pos) {
return pow($temp[$pos-1 ], (1/ $temp[$pos-2 ]));
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _power ($temp, $pos) {
return pow($temp[$pos-2 ], $temp[$pos-1 ]);
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _sin ($temp, $pos) {
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _cos ($temp, $pos) {
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _tan ($temp, $pos) {
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _asin ($temp, $pos) {
$angle = asin($temp[$pos-1 ]);
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _acos ($temp, $pos) {
$angle = acos($temp[$pos-1 ]);
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _atan ($temp, $pos) {
$angle = atan($temp[$pos-1 ]);
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _sqrt ($temp, $pos) {
return sqrt($temp[$pos-1 ]);
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _exp ($temp, $pos) {
return exp($temp[$pos-1 ]);
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _log ($temp, $pos) {
return log10($temp[$pos-1 ]);
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _ln ($temp, $pos) {
return log($temp[$pos-1 ]);
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _const_pi ($temp, $pos) {
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _const_e ($temp, $pos) {
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _E ($temp, $pos) {
return pow(10 , $temp[$pos-1 ]);
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _factorial ($temp, $pos) {
for($i=1; $i<= $temp[$pos-1 ]; $i++ ) {
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _abs ($temp, $pos) {
return abs($temp[$pos-1 ]);
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _mod ($temp, $pos) {
return $temp[$pos-2 ]% $temp[$pos-1 ];
* @param array $temp Temporary array
* @param integer $pos Position of operator
* @return float Function's relult
function _div ($temp, $pos) {
return floor($temp[$pos-2 ]/ $temp[$pos-1 ]);
* Calculate RPN Expression and return value
* @return float Result of input expression
$time1 = $this->_getMicroTime ();
if ($this->_error <> null ) {
$pos = $this->_nextOperator ($temp);
$this->_error = $this->_raiseError ('Syntax error');
$operator = $this->_operation[$temp[$pos]];
$function = $operator[3 ];
if (($arg==2 ) && (!isset ($temp[$pos-1 ]) || !is_numeric($temp[$pos-1 ]) || !isset ($temp[$pos-2 ]) || !is_numeric($temp[$pos-2 ]))) {
$this->_error = $this->_raiseError ('Syntax error');
} elseif (($arg==1 ) && (!isset ($temp[$pos-1 ]) || !is_numeric($temp[$pos-1 ]))) {
$this->_error = $this->_raiseError ('Syntax error');
if($arg==2 ) $arg_array = array ($temp[$pos-2 ],$temp[$pos-1 ]);
elseif ($arg==1 ) $arg_array = array ($temp[$pos-1 ]);
else $arg_array = array ();
if($function['type'] == 'userFunction') {
$function_array = array (&$function['class'], $function['method']);
$this->_value = $this->$function($temp, $pos);
if ($this->_isNan ($this->_value)) {
$this->_error = $this->_raiseError ('NAN value');
} elseif ($this->_isInfinite ($this->_value)) {
$this->_error = $this->_raiseError ('Infinite value');
} elseif (is_null($this->_value)) {
$temp = $this->_refresh ($temp, $pos, $arg, $this->_value);
} while (count($temp) > 1 );
$this->_value = $temp[0 ];
$time2 = $this->_getMicroTime ();
$this->_timer = $time2 - $time1;
* Return a time in second
* @return float Current time in seconds
function _getMicroTime () {
return ((float) $usec + (float) $sec);
Documentation generated on Fri, 24 Jul 2009 07:00:02 +0000 by phpDocumentor 1.4.2. PEAR Logo Copyright © PHP Group 2004.
|