2013-06-05 4 views
0

PHP의이 수학 표현식 파서와 계산기가 부동 소수점 연산에서 연산을 수행하지 않는 이유는 무엇입니까? 그리고 부동 소수점 연산을 수행하기 위해 어떻게 수정해야합니까? * 2 PHP 계산기가 부동 소수점 연산을 수행하지 않습니다.

부동 소수점 연산함으로써

, I 의미

  • 4.0

    • + 7.6

    5.0 또는

    • (8.1-10) *는 (3.0 ' ) 여기서

  • 코드이다

    <?php 
    
    require_once 'math.php'; 
    
    $math = new Math(); 
    
    if(isset($_GET['calc'])){ 
        $answer = $math->calculate($_GET['calc']); 
        echo $answer; 
    } 
    ?> 
    <!Doctype HTML> 
    <html lang="en"> 
         <head> 
          <meta charset="utf-8" /> 
          <title>calculator</title> 
        </head> 
        <body> 
        <form method="get"> 
         <input type="text" name="calc" autocomplete="off" autofocus /> 
        </form> 
        </body> 
    </html> 
    

    여기 math.php이다

    <?php 
    require_once 'stack.php'; 
    require_once 'terminalExpression.php'; 
    require_once 'expressions.php'; 
    
    class Math { 
    
        protected $variables = array(); 
    
        public function calculate($string) { 
         $stack = $this->parse($string); 
         return $this->run($stack); 
        } 
    
        public function parse($string) { 
         $tokens = $this->tokenize($string); 
         $output = new Stack(); 
         $operators = new Stack(); 
         foreach ($tokens as $token) { 
          $token = $this->extractVariables($token); 
          $expression = TerminalExpression::factory($token); 
          if ($expression->isOperator()) { 
           $this->parseOperator($expression, $output, $operators); 
          } elseif ($expression->isParenthesis()) { 
           $this->parseParenthesis($expression, $output, $operators); 
          } else { 
           $output->push($expression); 
          } 
         } 
         while (($op = $operators->pop())) { 
          if ($op->isParenthesis()) { 
           throw new RuntimeException('Mismatched Parenthesis'); 
          } 
          $output->push($op); 
         } 
         return $output; 
         } 
    
        public function registerVariable($name, $value) { 
         $this->variables[$name] = $value; 
        } 
    
        public function run(Stack $stack) { 
         while (($operator = $stack->pop()) && $operator->isOperator()) { 
          $value = $operator->operate($stack); 
          if (!is_null($value)) { 
           $stack->push(TerminalExpression::factory($value)); 
          } 
         } 
         return $operator ? $operator->render() : $this->render($stack); 
        } 
    
        protected function extractVariables($token) { 
         if ($token[0] == '$') { 
          $key = substr($token, 1); 
          return isset($this->variables[$key]) ? $this->variables[$key] : 0; 
         } 
         return $token; 
        } 
    
        protected function render(Stack $stack) { 
         $output = ''; 
         while (($el = $stack->pop())) { 
          $output .= $el->render(); 
         } 
         if ($output) { 
          return $output; 
         } 
         throw new RuntimeException('Could not render output'); 
        } 
    
        protected function parseParenthesis(TerminalExpression $expression, Stack $output, Stack $operators) { 
         if ($expression->isOpen()) { 
          $operators->push($expression); 
         } else { 
           $clean = false; 
           while (($end = $operators->pop())) { 
            if ($end->isParenthesis()) { 
            $clean = true; 
            break; 
            } else { 
            $output->push($end); 
           } 
           } 
           if (!$clean) { 
          throw new RuntimeException('Mismatched Parenthesis'); 
         } 
        } 
    } 
    
    protected function parseOperator(TerminalExpression $expression, Stack $output, Stack $operators) { 
        $end = $operators->poke(); 
        if (!$end) { 
         $operators->push($expression); 
        } elseif ($end->isOperator()) { 
         do { 
          if ($expression->isLeftAssoc() && $expression->getPrecidence() <= $end->getPrecidence()) { 
           $output->push($operators->pop()); 
          } elseif (!$expression->isLeftAssoc() && $expression->getPrecidence() < $end->getPrecidence()) { 
           $output->push($operators->pop()); 
          } else { 
           break; 
          } 
         } while (($end = $operators->poke()) && $end->isOperator()); 
         $operators->push($expression); 
        } else { 
         $operators->push($expression); 
        } 
    } 
    
    protected function tokenize($string) { 
        $parts = preg_split('((\d+|\+|-|\(|\)|\*|/)|\s+)', $string, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); 
        $parts = array_map('trim', $parts); 
        return $parts; 
    } 
    
    } 
    ?> 
    

    stack.php is :

    <?php 
    class Stack { 
    
        protected $data = array(); 
    
        public function push($element) { 
         $this->data[] = $element; 
        } 
    
        public function poke() { 
         return end($this->data); 
        } 
    
        public function pop() { 
         return array_pop($this->data); 
        } 
    
    } 
    ?> 
    
    ,451,515,

    및 terminalExpressions.php :

    <?php 
    abstract class TerminalExpression { 
    
    protected $value = ''; 
    
    public function __construct($value) { 
        $this->value = $value; 
    } 
    
    public static function factory($value) { 
        if (is_object($value) && $value instanceof TerminalExpression) { 
         return $value; 
        } elseif (is_numeric($value)) { 
         return new Number($value); 
        } elseif ($value == '+') { 
         return new Addition($value); 
        } elseif ($value == '-') { 
         return new Subtraction($value); 
        } elseif ($value == '*') { 
         return new Multiplication($value); 
        } elseif ($value == '/') { 
         return new Division($value); 
        } elseif (in_array($value, array('(', ')'))) { 
         return new Parenthesis($value); 
        } 
        throw new Exception('Undefined Value ' . $value); 
    } 
    
    abstract public function operate(Stack $stack); 
    
    public function isOperator() { 
        return false; 
    } 
    
    public function isParenthesis() { 
        return false; 
    } 
    
    public function isNoOp() { 
        return false; 
    } 
    
    public function render() { 
        return $this->value; 
    } 
    } 
    ?> 
    

    그리고 마지막으로 expressions.php :

    여기
    <?php 
    class Parenthesis extends TerminalExpression { 
    
    protected $precidence = 6; 
    
    public function operate(Stack $stack) { 
    } 
    
    public function getPrecidence() { 
        return $this->precidence; 
    } 
    
    public function isNoOp() { 
        return true; 
    } 
    
    public function isParenthesis() { 
        return true; 
    } 
    
    public function isOpen() { 
        return $this->value == '('; 
    } 
    
    } 
    
    class Number extends TerminalExpression { 
    
    public function operate(Stack $stack) { 
        return $this->value; 
    } 
    
    } 
    
    abstract class Operator extends TerminalExpression { 
    
    protected $precidence = 0; 
    protected $leftAssoc = true; 
    
    public function getPrecidence() { 
        return $this->precidence; 
    } 
    
    public function isLeftAssoc() { 
        return $this->leftAssoc; 
    } 
    
    public function isOperator() { 
        return true; 
    } 
    
    } 
    
    class Addition extends Operator { 
    
    protected $precidence = 4; 
    
    public function operate(Stack $stack) { 
        return $stack->pop()->operate($stack) + $stack->pop()->operate($stack); 
    } 
    
    } 
    
    class Subtraction extends Operator { 
    
    protected $precidence = 4; 
    
    public function operate(Stack $stack) { 
        $left = $stack->pop()->operate($stack); 
        $right = $stack->pop()->operate($stack); 
        return $right - $left; 
    } 
    
    } 
    
    class Multiplication extends Operator { 
    
    protected $precidence = 5; 
    
    public function operate(Stack $stack) { 
        return $stack->pop()->operate($stack) * $stack->pop()->operate($stack); 
    } 
    
    } 
    
    class Division extends Operator { 
    
    protected $precidence = 5; 
    
    public function operate(Stack $stack) { 
        $left = $stack->pop()->operate($stack); 
        $right = $stack->pop()->operate($stack); 
        return $right/$left; 
    } 
    
    } 
        ?> 
    
+2

작동하지 않는 테스트 케이스 목록과 대신 + 어떤 결과가 아닌 테스트 케이스 목록을 표시 할 수 있습니까? – Patashu

+3

이것은 너무 많은 코드입니다. 문제의 범위를 좁히십시오. – Blender

답변

1

Patashu의 솔루션입니다 더 완벽하지만 여전히 완료하려면 더 많은 일을해야합니다.

만 작동하도록 플로트 번호를 원하는 경우에 단지 그가 내가 당신의 경우에 그것을 시험이 하나

$parts = preg_split('(([0-9]*\.[0-9]+|[0-9]+|\+|-|\(|\)|\*|/)|\s+)', $string, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); 

$parts = preg_split('((\d+|\+|-|\(|\)|\*|/)|\s+)', $string, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); 

언급 라인을 변경하고 심지어이 0.2 같이 작동 * .4 + 1.4

이 솔루션은 부동 소수점 숫자에만 해당되며, Patashu의 답변을 작성하면 놀라운 계산기를 만들 것입니다.)

1

우리가 토큰 하나 개 이상의 숫자, A +하는 기대에 의해 수행되는 것을 볼 - (하는을 , a), A * A/또는 하나 이상의 공간 :

$parts = preg_split('((\d+|\+|-|\(|\)|\*|/)|\s+)', $string, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);

는 따라서 현재 부동 소수점 값을 인식 할 것이다.

당신은 예를

((\d*)?\.)?\d+([eE][+\-]?\d+)?|[nN]a[nN]|[iI]nf(inity)?

에 대한 선택의 부동 소수점 숫자 정규식이

\d+

을 변경 내가 많은 사람을 충당하기 위해 과거에 사용했던 하나입니다 필요 가능한 경우. 이 숫자 인 경우는 구문 분석 만 제대로 올바른 토큰으로 설정하지 않는 경우, 그래서 여기에

그것을 숫자로 토큰을 변환/숫자 나는 다음 여기에 보일 것이다

public static function factory($value) { 
    if (is_object($value) && $value instanceof TerminalExpression) { 
     return $value; 
    } elseif (is_numeric($value)) { 
     return new Number($value); 
+0

공장 기능을 사용하려면 무엇을하고 싶습니까? – JayGatz

+0

@JayGatz "... 그래서 구문 분석하면 올바른 토큰/번호로 바뀌지 않습니다. 다음에 보겠습니다."변경 1이 문제를 완전히 해결하지 못했다면, 이것이 내가 원하는 부분입니다. 다음 봐. – Patashu

+0

그 부분을 얻었지만 공장 기능을 사용하려면 어떻게 해야할지 모르겠다. 의견 있으십니까? – JayGatz

관련 문제