有个网友写信给我谈到关于PHP计算工资问题。我以前一篇文章中谈到过一种计算工资的方法,不过是偷巧,利用现有的表达式的工具,现在既然有人想要,我就给出一个逆波兰的算法。
我们的目标是实现如下的计算公式:
假设有一个计算公式如下: $expression = "(F1*F12+10.34)";
其中的变量值如下:
$expression_value = Array('F1'=>10,
'F12'=>20);
我们希望用PHP构建一个类来计算出这个表达式的值。这种应用主要用于web工资管理中,用户可以自定义其工资相公式的情况
$rpn = new Math_Rpn();
$rpn->setExpressionValue($expression_value);
echo $rpn->calculate($expression,'deg',false); // 即为相应的值
解析逆波兰表达式的方法,编译原理中有,就是先把表达式分解成符号数组,然后求逆波兰式,最后根据逆波兰式得到其结果。
我分别把三个函数贴在下面,其实本质我就是对Pear的RPN函数进行了Hack.
function _stringToArray () {
$temp_operator = null;
$temp_value = null;
$this->_input = str_replace(" ","",$this->_input);
for($i = 0; $i < strlen($this->_input); $i++) {
if ($this->_input[$i] == ' ') {
if ($temp_operator != null) {
array_push($this->_input_array, $temp_operator);
$temp_operator = null;
}
if ($temp_value != null) {
array_push($this->_input_array, $temp_value);
$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) {
array_push($this->_input_array, $temp_operator);
$temp_operator = null;
}
array_push($this->_input_array, '-1');
array_push($this->_input_array, '*');
//} elseif ((is_numeric($this->_input[$i])) || ($this->_input[$i] == '.')) {
} elseif ((is_numeric($this->_input[$i])) || ($this->_input[$i] == '.') || ($this->_input[$i] == 'F')) {
if ($temp_operator != null) {
array_push($this->_input_array, $temp_operator);
$temp_operator = null;
}
$temp_value .= $this->_input[$i];
} else {
if ($this->_keyExists($temp_operator, $this->_operation, 1)) {
array_push($this->_input_array, $temp_operator);
$temp_operator = null;
}
if ($temp_value != null) {
array_push($this->_input_array, $temp_value);
$temp_value = null;
}
$temp_operator .= $this->_input[$i];
}
}
if ($temp_operator != null && $temp_operator != ' ') {
array_push($this->_input_array, $temp_operator);
} elseif($temp_value != null && $temp_value != ' ') {
array_push($this->_input_array, $temp_value);
}
// $this->_testInput();
print_r($this->_expression_value);
print_r($this->_input_array);
return $this->_input_array;
}
function _arrayToRpn() {
if ($this->_error <> null) {
$this->_output = array();
return $this->_output;
}
for($i = 0; $i < count($this->_input_array); $i++) {
$temp = $this->_input_array[$i];
if (is_numeric($temp)) {
$this->_outputAdd($temp);
} else if($this->_keyExists($temp, $this->_expression_value, 0)) {
$this->_outputAdd($this->_expression_value[$temp]);
} else {
if ($temp == ')') {
while(!$this->_stackEmpty() && ($this->_stackPriority() >= 1)) {
$this->_outputAdd($this->_stackDelete());
}
if (!$this->_stackEmpty()) {
$this->_stackDelete();
}
} elseif ($temp=='(') {
$this->_stackAdd($temp);
} elseif (($this->_stackEmpty()) || (($this->_priority($temp) > $this->_stackPriority()))) {
$this-> _stackAdd($temp);
} else {
while(!$this->_stackEmpty() && ($this->_priority($temp) <= $this->_stackPriority())) {
$this->_outputAdd($this->_stackDelete());
}
$this->_stackAdd($temp);
}
}
}
while(!$this->_stackEmpty()) {
$this->_outputAdd($this->_stackDelete());
}
return $this->_output;
}
function _rpnToValue() {
$time1 = $this->_getMicroTime();
if ($this->_error <> null) {
$this->_value = null;
return $this->_value;
}
$this->_value = 0;
$temp = $this->_output;
do {
$pos = $this->_nextOperator($temp);
if ($pos == -1) {
$this->_error = $this->_raiseError('Syntax error');
$this->_value = null;
return $this->_value;
}
$operator = $this->_operation[$temp[$pos]];
$arg = $operator[2];
$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');
$this->_value = null;
return $this->_value;
} elseif (($arg==1) && (!isset($temp[$pos-1]) || !is_numeric($temp[$pos-1]))) {
$this->_error = $this->_raiseError('Syntax error');
$this->_value = null;
return $this->_value;
}
if(is_array($function)) {
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') {
$this->_value = call_user_func_array($function['function'], $arg_array);
} else {
$function_array = array(&$function['class'], $function['method']);
$this->_value = call_user_func_array($function_array, $arg_array);
}
} else {
$this->_value = $this->$function($temp, $pos);
}
if ($this->_isNan($this->_value)) {
$this->_error = $this->_raiseError('NAN value');
$this->_value = null;
return $this->_value;
} elseif ($this->_isInfinite($this->_value)) {
$this->_error = $this->_raiseError('Infinite value');
$this->_value = null;
return $this->_value;
} elseif (is_null($this->_value)) {
return $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 $this->_value;
}
分享到:
相关推荐
逆波兰表达式,又称后缀表达式,是一种用于表示数学计算的符号表示法。它将操作符放在操作数之后,避免了使用括号,简化了运算过程。在基于逆波兰表达式的计算程序中,通常包括以下几个核心知识点: 1. **逆波兰...
### 逆波兰表达式及其算法实现 #### 一、引言 逆波兰表达式(Reverse Polish Notation, RPN)是一种特殊的数学表达式表示方法,它最初由波兰逻辑学家Jan Łukasiewicz提出。与传统的中缀表达式相比,逆波兰表达式...
- 计算逆波兰表达式通常使用栈数据结构。 - 遍历表达式字符串,遇到数字时入栈,遇到运算符时弹出栈顶两个元素进行运算,并将结果压回栈。 - 按照运算符的优先级进行操作,没有优先级冲突。 3. **括号匹配** - ...
逆波兰表达式(Reverse Polish Notation,RPN)是一种数学表达式表示方法,它将操作符放在操作数之后,使得表达式无需括号就能清晰地表明运算顺序。在本题中,我们需要用Python来实现一个逆波兰表达式求值器。这在...
这段代码中,`evalRPN`函数接收一个包含逆波兰表达式元素的数组,`isNumber`函数判断字符串是否为数字,`applyOperation`函数根据运算符进行相应的计算。整个解题过程中,我们使用了栈来存储中间计算结果,保证了...
通过这样的实现,我们可以有效地计算逆波兰表达式,不仅简化了表达式的求值过程,还提高了计算效率。逆波兰表达式在编译器设计、计算器程序以及其他需要解析和计算数学表达式的地方都有广泛的应用。
逆波兰表达式计算源码是实现逆波兰表达式求值的程序代码。在易语言中,我们可以利用栈这一数据结构来实现逆波兰表达式的计算。栈是一种先进后出(FILO)的数据结构,非常适合处理后缀表达式,因为它可以按运算符出现...
这段伪代码简洁明了地展示了如何使用一个栈来计算逆波兰表达式的值。通过这种方法,我们可以高效地处理复杂的数学表达式,避免了传统中缀表达式解析时所需的括号匹配和运算符优先级判断等问题。 总之,逆波兰表达式...
逆波兰表达式求值是计算机科学中的一个重要概念,主要用于避免使用括号来表示运算优先级,从而简化表达式的解析过程。逆波兰表达式,又称后缀表达式,是一种没有括号、无需考虑运算符优先级的数学表达式书写方式。在...
在易语言中,逆波兰表达式计算通常涉及到字符串处理、栈数据结构以及算法设计等多个知识点。 易语言是中国的一种计算机编程语言,它的设计目标是使用户能够以接近自然语言的方式来编写程序。逆波兰表达式计算在...
在计算逆波兰表达式时,我们通常会用到两个栈:一个用来存储操作数,另一个用来存储运算符。以下是利用栈计算逆波兰表达式的步骤: 1. 初始化两个空栈,一个为操作数栈,一个为运算符栈。 2. 从左到右扫描逆波兰...
逆波兰表达式(Reverse Polish Notation...总的来说,逆波兰表达式计算器项目是理解和实现计算逻辑的一个良好实践,同时也提供了扩展和自定义的可能性,对于学习数据结构和算法,特别是栈的应用,具有很高的教育价值。
逆波兰算术表达式,又称后缀表达式,是一种没有括号且运算符放在操作数后面的表示法。这种表示方式简化了表达式的计算过程,特别适用于计算机程序处理。本篇文章将探讨如何使用JavaScript来实现逆波兰算术表达式解析...
逆波兰法,也被称为后缀表达式,是一种在计算领域广泛应用的算法,特别是在设计和实现计算器或编译器时。这种表示法将运算符置于其操作数之后,从而避免了括号的使用,并简化了计算过程。对于支持浮点数的计算器而言...
在Delphi中实现逆波兰表达式转换,首先我们需要一个算法来解析输入的中缀表达式,并将其转化为逆波兰表达式。这个过程通常分为两个步骤:扫描和推入。扫描过程中,我们读取每一个字符,如果是数字,则直接将其作为...
本实验“编译原理 实验 (计算器 语法树 逆波兰表达式)”着重于理解和应用编译器的一些核心概念,特别是与计算、语法分析和后缀表达式相关的部分。 首先,我们关注“计算器”部分。一个计算器程序通常包含输入解析...
计算逆波兰表达式通常采用栈数据结构,遵循“后进先出”(LIFO)原则。首先,将所有数字压入栈中;然后,遇到运算符时,弹出栈顶的两个数值进行运算,并将结果压回栈中。如此反复,直到表达式末尾,最后栈中剩下的...
其中,中缀表达式是我们通常使用的运算符在操作数之间的形式,如 "2 + 3 * 4",而后缀表达式,也称为逆波兰表达式,是一种将运算符置于操作数之后的表示方式,例如 "2 3 4 *" 表示 "2 加上 3 乘以 4" 的结果。...