Issue
This question has a short answer. Using the eval()
method causes php to fully resolve the formula and return the correct result.
$expression = "27+38+81+48*33*53+91*53+82*14+96";
$result = eval('return '.$expression.';');
$ Echo the result.
How can I solve this problem without using eval()
?
Solution
The functions below will parse simple mathematical expressions and calculate the result.
<?php
echo "90165: ".calculate("27+38+81+48*33*53+91*53+82*14+96")."\n";
// calculates the result of an expression in infix notation
function calculate($exp) {
return calculate_rpn(mathexp_to_rpn($exp));
}
// calculates the result of an expression in reverse polish notation
function calculate_rpn($rpnexp) {
$stack = array();
foreach($rpnexp as $item) {
if (is_operator($item)) {
if ($item == '+') {
$j = array_pop($stack);
$i = array_pop($stack);
array_push($stack, $i + $j);
}
if ($item == '-') {
$j = array_pop($stack);
$i = array_pop($stack);
array_push($stack, $i - $j);
}
if ($item == '*') {
$j = array_pop($stack);
$i = array_pop($stack);
array_push($stack, $i * $j);
}
if ($item == '/') {
$j = array_pop($stack);
$i = array_pop($stack);
array_push($stack, $i / $j);
}
if ($item == '%') {
$j = array_pop($stack);
$i = array_pop($stack);
array_push($stack, $i % $j);
}
} else {
array_push($stack, $item);
}
}
return $stack[0];
}
// converts infix notation to reverse polish notation
function mathexp_to_rpn($mathexp) {
$precedence = array(
'(' => 0,
'-' => 3,
'+' => 3,
'*' => 6,
'/' => 6,
'%' => 6
);
$i = 0;
$final_stack = array();
$operator_stack = array();
while ($i < strlen($mathexp)) {
$char = $mathexp{$i};
if (is_number($char)) {
$num = readnumber($mathexp, $i);
array_push($final_stack, $num);
$i += strlen($num); continue;
}
if (is_operator($char)) {
$top = end($operator_stack);
if ($top && $precedence[$char] <= $precedence[$top]) {
$oper = array_pop($operator_stack);
array_push($final_stack, $oper);
}
array_push($operator_stack, $char);
$i++; continue;
}
if ($char == '(') {
array_push($operator_stack, $char);
$i++; continue;
}
if ($char == ')') {
// transfer operators to final stack
do {
$operator = array_pop($operator_stack);
if ($operator == '(') break;
array_push($final_stack, $operator);
} while ($operator);
$i++; continue;
}
$i++;
}
while ($oper = array_pop($operator_stack)) {
array_push($final_stack, $oper);
}
return $final_stack;
}
function readnumber($string, $i) {
$number = '';
while (is_number($string{$i})) {
$number .= $string{$i};
$i++;
}
return $number;
}
function is_operator($char) {
static $operators = array('+', '-', '/', '*', '%');
return in_array($char, $operators);
}
function is_number($char) {
return (($char == '.') || ($char >= '0' && $char <= '9'));
}
?>
The function mathexp_to_rpn()
converts a mathematical expression in infix notation, like "3 + 2"
to an expression in reverse polish notation (RPN): "3 2 +"
. This is easier to calculate, which is done by the function calculate_rpn()
. Operator precedence and parenthesis is taken into account. There is no checking whether the input is a valid expression. Dividing is not very precise.
Answered By – noah1400
Answer Checked By – Candace Johnson (Easybugfix Volunteer)