/** * Evaluate a FunctionNode * * Computes the value of a FunctionNode `f(x)`, where f is * an elementary function recognized by StdMathLexer and StdMathParser. * * @see \MathParser\Lexer\StdMathLexer StdMathLexer * @see \MathParser\StdMathParser StdMathParser * @throws UnknownFunctionException if the function respresented by the * FunctionNode is *not* recognized. * * @param FunctionNode $node AST to be evaluated * @retval float */ public function visitFunctionNode(FunctionNode $node) { $inner = $node->getOperand()->accept($this); switch ($node->getName()) { // Trigonometric functions case 'sin': case 'cos': case 'tan': case 'cot': case 'arcsin': case 'arccos': case 'arctan': case 'arccot': case 'exp': case 'log': case 'lg': case 'sinh': case 'cosh': case 'tanh': case 'coth': case 'arsinh': case 'arcosh': case 'artanh': case 'arcoth': throw new \UnexpectedValueException("Expecting rational expression"); case 'abs': return new RationalNode(abs($inner->getNumerator()), $inner->getDenominator()); case 'sgn': if ($inner->getNumerator() >= 0) { return new RationalNode(1, 0); } else { return new RationalNode(-1, 0); } // Powers // Powers case 'sqrt': return $this->rpow($inner, new RationalNode(1, 2)); case '!': if ($inner->getDenominator() == 1 && $inner->getNumerator() >= 0) { return new RationalNode(Math::Factorial($inner->getNumerator()), 1); } throw new \UnexpectedValueException("Expecting positive integer (factorial)"); case '!!': if ($inner->getDenominator() == 1 && $inner->getNumerator() >= 0) { return new RationalNode(Math::SemiFactorial($inner->getNumerator()), 1); } throw new \UnexpectedValueException("Expecting positive integer (factorial)"); default: throw new UnknownFunctionException($node->getName()); } }
public function testFactorial() { $this->assertEquals(1, Math::Factorial(0)); $this->assertEquals(6, Math::Factorial(3)); $this->assertEquals(362880, Math::Factorial(9)); }