Parser.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. <?php
  2. /*
  3. * MODIFICATIONS
  4. * - Removed `\` for php5.2 support (does not support namespaces).
  5. * - Renamed with prefix to avoid naming collisions.
  6. * - Updated references to the EOS Stack class to reflect name changes.
  7. */
  8. /**
  9. * Equation Operating System Classes.
  10. *
  11. * This class was created for the safe parsing of mathematical equations
  12. * in PHP. There is a need for a way to successfully parse equations
  13. * in PHP that do NOT require the use of `eval`. `eval` at its core
  14. * opens the system using it to so many security vulnerabilities it is oft
  15. * suggested /never/ to use it, and for good reason. This class set will
  16. * successfully take an equation, parse it, and provide solutions to the
  17. * developer. It is a safe way to evaluate expressions without putting
  18. * the system at risk.
  19. *
  20. * 2015/07
  21. * - Added all real number factorial support
  22. * - Added gamma function to class
  23. *
  24. * 2014/08
  25. * - Added scientific notation support
  26. * - Added basic factorial support
  27. *
  28. * 2013/06 UPDATE:
  29. * - Added 'abs' (absolute value) support per tjbaron's update.
  30. *
  31. * 2013/04 UPDATE:
  32. * - Moved to native class functions for PHP5
  33. * - Removed deprecated `eregi` calls to `preg_match`
  34. * - Updated to PHPDoc comment syntax
  35. * - Added Exception throwing instead of silent exits
  36. * - Added additional variable prefix of '$', '&' is still allowed as well
  37. * - Fixed small implied multiplication problem
  38. *
  39. * @author Jon Lawrence <jlawrence11@gmail.com>
  40. * @copyright Copyright 2005-2015, Jon Lawrence
  41. * @license http://opensource.org/licenses/LGPL-2.1 LGPL 2.1 License
  42. * @package EOS
  43. * @version 2.2.1
  44. */
  45. require_once 'Stack.php';
  46. /**
  47. * Equation Operating System (EOS) Parser
  48. *
  49. * An EOS that can safely parse equations from unknown sources returning
  50. * the calculated value of it. Can also handle solving equations with
  51. * variables, if the variables are defined (useful for the Graph creation
  52. * that the second and extended class in this file provides. {@see eqGraph})
  53. * This class was created for PHP4 in 2005, updated to fully PHP5 in 2013.
  54. *
  55. * @author Jon Lawrence <jlawrence11@gmail.com>
  56. * @copyright Copyright �2005-2013, Jon Lawrence
  57. * @license http://opensource.org/licenses/LGPL-2.1 LGPL 2.1 License
  58. * @package Math
  59. * @subpackage EOS
  60. * @version 2.2.1
  61. */
  62. class NF_EOS_Parser {
  63. /**
  64. * No matching Open/Close pair
  65. */
  66. const E_NO_SET = 5500;
  67. /**
  68. * Division by 0
  69. */
  70. const E_DIV_ZERO = 5501;
  71. /**
  72. * No Equation
  73. */
  74. const E_NO_EQ = 5502;
  75. /**
  76. * No variable replacement available
  77. */
  78. const E_NO_VAR = 5503;
  79. /**
  80. * Not a number
  81. */
  82. const E_NAN = 5504;
  83. /**
  84. * @var bool Activate Debug output.
  85. * @see __construct()
  86. * @see solveIF()
  87. */
  88. public static $debug = FALSE;
  89. /**#@+
  90. *Private variables
  91. */
  92. private $postFix;
  93. private $inFix;
  94. /**#@-*/
  95. /**#@+
  96. * Protected variables
  97. */
  98. //What are opening and closing selectors
  99. protected $SEP = array('open' => array('(', '['), 'close' => array(')', ']'));
  100. //Top presedence following operator - not in use
  101. protected $SGL = array('!');
  102. //Order of operations arrays follow
  103. protected $ST = array('^', '!');
  104. protected $ST1 = array('/', '*', '%');
  105. protected $ST2 = array('+', '-');
  106. //Allowed functions
  107. protected $FNC = array('sin', 'cos', 'tan', 'csc', 'sec', 'cot', 'abs', 'log', 'log10', 'sqrt');
  108. /**#@-*/
  109. /**
  110. * Construct method
  111. *
  112. * Will initiate the class. If variable given, will assign to
  113. * internal variable to solve with this::solveIF() without needing
  114. * additional input. Initializing with a variable is not suggested.
  115. *
  116. * @see Parser::solveIF()
  117. * @param String $inFix Standard format equation
  118. */
  119. public function __construct($inFix = null) {
  120. if(defined('DEBUG') && DEBUG) {
  121. self::$debug = true;
  122. }
  123. $this->inFix = (isset($inFix)) ? $inFix : null;
  124. $this->postFix = array();
  125. }
  126. /**
  127. * Check Infix for opening closing pair matches.
  128. *
  129. * This function is meant to solely check to make sure every opening
  130. * statement has a matching closing one, and throws an exception if
  131. * it doesn't.
  132. *
  133. * @param String $infix Equation to check
  134. * @throws Exception if malformed.
  135. * @return Bool true if passes - throws an exception if not.
  136. */
  137. private function checkInfix($infix) {
  138. if(trim($infix) == "") {
  139. throw new Exception("No Equation given", NF_EOS_Parser::E_NO_EQ);
  140. }
  141. //Make sure we have the same number of '(' as we do ')'
  142. // and the same # of '[' as we do ']'
  143. if(substr_count($infix, '(') != substr_count($infix, ')')) {
  144. throw new Exception("Mismatched parenthesis in '{$infix}'", NF_EOS_Parser::E_NO_SET);
  145. } elseif(substr_count($infix, '[') != substr_count($infix, ']')) {
  146. throw new Exception("Mismatched brackets in '{$infix}'", NF_EOS_Parser::E_NO_SET);
  147. }
  148. $this->inFix = $infix;
  149. return true;
  150. }
  151. /**
  152. * Infix to Postfix
  153. *
  154. * Converts an infix (standard) equation to postfix (RPN) notation.
  155. * Sets the internal variable $this->postFix for the Parser::solvePF()
  156. * function to use.
  157. *
  158. * @link http://en.wikipedia.org/wiki/Infix_notation Infix Notation
  159. * @link http://en.wikipedia.org/wiki/Reverse_Polish_notation Reverse Polish Notation
  160. * @param String $infix A standard notation equation
  161. * @throws Exception When parenthesis are mismatched.
  162. * @return Array Fully formed RPN Stack
  163. */
  164. public function in2post($infix = null) {
  165. // if an equation was not passed, use the one that was passed in the constructor
  166. $infix = (isset($infix)) ? $infix : $this->inFix;
  167. //check to make sure 'valid' equation
  168. $this->checkInfix($infix);
  169. $pf = array();
  170. $ops = new NF_EOS_Stack();
  171. //$vars = new Stack();
  172. // remove all white-space
  173. $infix = preg_replace("/\s/", "", $infix);
  174. // Create postfix array index
  175. $pfIndex = 0;
  176. //what was the last character? (useful for decerning between a sign for negation and subtraction)
  177. $lChar = '';
  178. //loop through all the characters and start doing stuff ^^
  179. for($i=0;$i<strlen($infix);$i++) {
  180. // pull out 1 character from the string
  181. $chr = substr($infix, $i, 1);
  182. // if the character is numerical
  183. if(preg_match('/[0-9.]/i', $chr)) {
  184. // if the previous character was not a '-' or a number
  185. if((!preg_match('/[0-9.]/i', $lChar) && ($lChar != "")) && (isset($pf[$pfIndex]) && ($pf[$pfIndex]!="-")))
  186. $pfIndex++; // increase the index so as not to overlap anything
  187. // Add the number character to the array
  188. if(isset($pf[$pfIndex])) {
  189. $pf[$pfIndex] .= $chr;
  190. } else {
  191. $pf[$pfIndex] = $chr;
  192. }
  193. }
  194. // If the character opens a set e.g. '(' or '['
  195. elseif(in_array($chr, $this->SEP['open'])) {
  196. // if the last character was a number, place an assumed '*' on the stack
  197. if(preg_match('/[0-9.]/i', $lChar))
  198. $ops->push('*');
  199. $ops->push($chr);
  200. }
  201. // if the character closes a set e.g. ')' or ']'
  202. elseif(in_array($chr, $this->SEP['close'])) {
  203. // find what set it was i.e. matches ')' with '(' or ']' with '['
  204. $key = array_search($chr, $this->SEP['close']);
  205. // while the operator on the stack isn't the matching pair...pop it off
  206. while($ops->peek() != $this->SEP['open'][$key]) {
  207. $nchr = $ops->pop();
  208. if($nchr)
  209. $pf[++$pfIndex] = $nchr;
  210. else {
  211. throw new Exception("Error while searching for '". $this->SEP['open'][$key] ."' in '{$infix}'.", NF_EOS_Parser::E_NO_SET);
  212. }
  213. }
  214. $ops->pop();
  215. }
  216. // If a special operator that has precedence over everything else
  217. elseif(in_array($chr, $this->ST)) {
  218. while(in_array($ops->peek(), $this->ST))
  219. $pf[++$pfIndex] = $ops->pop();
  220. $ops->push($chr);
  221. $pfIndex++;
  222. }
  223. // Any other operator other than '+' and '-'
  224. elseif(in_array($chr, $this->ST1)) {
  225. while(in_array($ops->peek(), $this->ST1) || in_array($ops->peek(), $this->ST))
  226. $pf[++$pfIndex] = $ops->pop();
  227. $ops->push($chr);
  228. $pfIndex++;
  229. }
  230. // if a '+' or '-'
  231. elseif(in_array($chr, $this->ST2)) {
  232. // if it is a '-' and the character before it was an operator or nothingness (e.g. it negates a number)
  233. if((in_array($lChar, array_merge($this->ST1, $this->ST2, $this->ST, $this->SEP['open'])) || $lChar=="") && $chr=="-") {
  234. // increase the index because there is no reason that it shouldn't..
  235. $pfIndex++;
  236. $pf[$pfIndex] = $chr;
  237. }
  238. // Otherwise it will function like a normal operator
  239. else {
  240. while(in_array($ops->peek(), array_merge($this->ST1, $this->ST2, $this->ST)))
  241. $pf[++$pfIndex] = $ops->pop();
  242. $ops->push($chr);
  243. $pfIndex++;
  244. }
  245. }
  246. // make sure we record this character to be referred to by the next one
  247. $lChar = $chr;
  248. }
  249. // if there is anything on the stack after we are done...add it to the back of the RPN array
  250. while(($tmp = $ops->pop()) !== false)
  251. $pf[++$pfIndex] = $tmp;
  252. // re-index the array at 0
  253. $pf = array_values($pf);
  254. // set the private variable for later use if needed
  255. $this->postFix = $pf;
  256. // return the RPN array in case developer wants to use it fro some insane reason (bug testing ;]
  257. return $pf;
  258. } //end function in2post
  259. /**
  260. * Solve Postfix (RPN)
  261. *
  262. * This function will solve a RPN array. Default action is to solve
  263. * the RPN array stored in the class from Parser::in2post(), can take
  264. * an array input to solve as well, though default action is preferred.
  265. *
  266. * @link http://en.wikipedia.org/wiki/Reverse_Polish_notation Postix Notation
  267. * @param Array $pfArray RPN formatted array. Optional.
  268. * @throws Exception On division by zero.
  269. * @return Float Result of the operation.
  270. */
  271. public function solvePF($pfArray = null) {
  272. // if no RPN array is passed - use the one stored in the private var
  273. $pf = (!is_array($pfArray)) ? $this->postFix : $pfArray;
  274. // create our temporary function variables
  275. $temp = array();
  276. //$tot = 0;
  277. $hold = 0;
  278. // Loop through each number/operator
  279. for($i=0;$i<count($pf); $i++) {
  280. // If the string isn't an operator, add it to the temp var as a holding place
  281. if(!in_array($pf[$i], array_merge($this->ST, $this->ST1, $this->ST2))) {
  282. $temp[$hold++] = $pf[$i];
  283. }
  284. // ...Otherwise perform the operator on the last two numbers
  285. else {
  286. switch ($pf[$i]) {
  287. case '+':
  288. $temp[$hold-2] = $temp[$hold-2] + $temp[$hold-1];
  289. break;
  290. case '-':
  291. $temp[$hold-2] = $temp[$hold-2] - $temp[$hold-1];
  292. break;
  293. case '*':
  294. $temp[$hold-2] = $temp[$hold-2] * $temp[$hold-1];
  295. break;
  296. case '/':
  297. if($temp[$hold-1] == 0) {
  298. throw new Exception("Division by 0 on: '{$temp[$hold-2]} / {$temp[$hold-1]}' in {$this->inFix}", NF_EOS_Parser::E_DIV_ZERO);
  299. }
  300. $temp[$hold-2] = $temp[$hold-2] / $temp[$hold-1];
  301. break;
  302. case '^':
  303. $temp[$hold-2] = pow($temp[$hold-2], $temp[$hold-1]);
  304. break;
  305. case '!':
  306. $temp[$hold-1] = $this->factorial($temp[$hold-1]);
  307. $hold++;
  308. break;
  309. case '%':
  310. if($temp[$hold-1] == 0) {
  311. throw new Exception("Division by 0 on: '{$temp[$hold-2]} % {$temp[$hold-1]}' in {$this->inFix}", NF_EOS_Parser::E_DIV_ZERO);
  312. }
  313. $temp[$hold-2] = bcmod($temp[$hold-2], $temp[$hold-1]);
  314. break;
  315. }
  316. // Decrease the hold var to one above where the last number is
  317. $hold = $hold-1;
  318. }
  319. }
  320. // return the last number in the array
  321. return $temp[$hold-1];
  322. } //end function solvePF
  323. public function solve($equation, $values = null) {
  324. if(is_array($equation)) {
  325. return $this->solvePF($equation);
  326. } else {
  327. return $this->solveIF($equation, $values);
  328. }
  329. }
  330. /**
  331. * Solve Infix (Standard) Notation Equation
  332. *
  333. * Will take a standard equation with optional variables and solve it. Variables
  334. * must begin with '&' or '$'
  335. * The variable array must be in the format of 'variable' => value. If
  336. * variable array is scalar (ie 5), all variables will be replaced with it.
  337. *
  338. * @param String $infix Standard Equation to solve
  339. * @param String|Array $vArray Variable replacement
  340. * @throws Exception On division by zero and on NaN and lack of variable replacement.
  341. * @return Float Solved equation
  342. */
  343. function solveIF($infix, $vArray = null) {
  344. $infix = ($infix != "") ? $infix : $this->inFix;
  345. //Check to make sure a 'valid' expression
  346. $this->checkInfix($infix);
  347. //$ops = new Stack();
  348. //$vars = new Stack();
  349. $hand = null;
  350. //remove all white-space
  351. $infix = preg_replace("/\s/", "", $infix);
  352. if(NF_EOS_Parser::$debug) {
  353. $hand=fopen("eq.txt","a");
  354. }
  355. //replace scientific notation with normal notation (2e-9 to 2*10^-9)
  356. $infix = preg_replace('/([\d])([eE])(-?\d)/', '$1*10^$3', $infix);
  357. if(NF_EOS_Parser::$debug) {
  358. fwrite($hand, "$infix\n");
  359. }
  360. // Finds all the 'functions' within the equation and calculates them
  361. // NOTE - when using function, only 1 set of parenthesis will be found, instead use brackets for sets within functions!!
  362. //while((preg_match("/(". implode("|", $this->FNC) . ")\(([^\)\(]*(\([^\)]*\)[^\(\)]*)*[^\)\(]*)\)/", $infix, $match)) != 0) {
  363. //Nested parenthesis are now a go!
  364. while((preg_match("/(". implode("|", $this->FNC) . ")\(((?:[^()]|\((?2)\))*+)\)/", $infix, $match)) != 0) {
  365. $func = $this->solveIF($match[2], $vArray);
  366. switch($match[1]) {
  367. case "cos":
  368. $ans = cos($func);
  369. break;
  370. case "sin":
  371. $ans = sin($func);
  372. break;
  373. case "tan":
  374. $ans = tan($func);
  375. break;
  376. case "sec":
  377. $tmp = cos($func);
  378. if($tmp == 0) {
  379. throw new Exception("Division by 0 on: 'sec({$func}) = 1/cos({$func})' in {$this->inFix}", NF_EOS_Parser::E_DIV_ZERO);
  380. }
  381. $ans = 1/$tmp;
  382. break;
  383. case "csc":
  384. $tmp = sin($func);
  385. if($tmp == 0) {
  386. throw new Exception("Division by 0 on: 'csc({$func}) = 1/sin({$func})' in {$this->inFix}", NF_EOS_Parser::E_DIV_ZERO);
  387. }
  388. $ans = 1/$tmp;
  389. break;
  390. case "cot":
  391. $tmp = tan($func);
  392. if($tmp == 0) {
  393. throw new Exception("Division by 0 on: 'cot({$func}) = 1/tan({$func})' in {$this->inFix}", NF_EOS_Parser::E_DIV_ZERO);
  394. }
  395. $ans = 1/$tmp;
  396. break;
  397. case "abs":
  398. $ans = abs($func);
  399. break;
  400. case "log":
  401. $ans = log($func);
  402. if(is_nan($ans) || is_infinite($ans)) {
  403. throw new Exception("Result of 'log({$func}) = {$ans}' is either infinite or a non-number in {$this->inFix}", NF_EOS_Parser::E_NAN);
  404. }
  405. break;
  406. case "log10":
  407. $ans = log10($func);
  408. if(is_nan($ans) || is_infinite($ans)) {
  409. throw new Exception("Result of 'log10({$func}) = {$ans}' is either infinite or a non-number in {$this->inFix}", NF_EOS_Parser::E_NAN);
  410. }
  411. break;
  412. case "sqrt":
  413. if($func < 0) {
  414. throw new Exception("Result of 'sqrt({$func}) = i. We can't handle imaginary numbers", NF_EOS_Parser::E_NAN);
  415. }
  416. $ans = sqrt($func);
  417. break;
  418. default:
  419. $ans = 0;
  420. break;
  421. }
  422. $infix = str_replace($match[0], "({$ans})", $infix);
  423. }
  424. $infix = preg_replace('/[$&]/', "", $infix);
  425. //Find all the variables that were passed and replaces them
  426. while((preg_match('/([^a-zA-Z]){0,1}([a-zA-Z]+)([^a-zA-Z]){0,1}/', $infix, $match)) != 0) {
  427. //remove notices by defining if undefined.
  428. if(!isset($match[3])) {
  429. $match[3] = "";
  430. }
  431. if(NF_EOS_Parser::$debug)
  432. fwrite($hand, "{$match[1]} || {$match[3]}\n");
  433. // Ensure that the variable has an operator or something of that sort in front and back - if it doesn't, add an implied '*'
  434. if((!in_array($match[1], array_merge($this->ST, $this->ST1, $this->ST2, $this->SEP['open'])) && $match[1] != "") || is_numeric($match[1])) //$this->SEP['close'] removed
  435. $front = "*";
  436. else
  437. $front = "";
  438. if((!in_array($match[3], array_merge($this->ST, $this->ST1, $this->ST2, $this->SEP['close'])) && $match[3] != "") || is_numeric($match[3])) //$this->SEP['open'] removed
  439. $back = "*";
  440. else
  441. $back = "";
  442. //Make sure that the variable does have a replacement
  443. //First check for pi and e variables that wll automagically be replaced
  444. if(in_array(strtolower($match[2]), array('pi', 'e'))) {
  445. $t = (strtolower($match[2])=='pi') ? pi() : exp(1);
  446. $infix = str_replace($match[0], $match[1] . $front. $t. $back . $match[3], $infix);
  447. } elseif(!isset($vArray[$match[2]]) && (!is_array($vArray != "") && !is_numeric($vArray) && 0 !== $vArray)) {
  448. throw new Exception("Variable replacement does not exist for '". substr($match[0], 1, 1). $match[2] ."' in {$this->inFix}", NF_EOS_Parser::E_NO_VAR);
  449. } elseif(!isset($vArray[$match[2]]) && (!is_array($vArray != "") && is_numeric($vArray))) {
  450. $infix = str_replace($match[0], $match[1] . $front. $vArray. $back . $match[3], $infix);
  451. } elseif(isset($vArray[$match[2]])) {
  452. $infix = str_replace($match[0], $match[1] . $front. $vArray[$match[2]]. $back . $match[3], $infix);
  453. }
  454. }
  455. if(NF_EOS_Parser::$debug)
  456. fclose($hand);
  457. return $this->solvePF($this->in2post($infix));
  458. } //end function solveIF
  459. /**
  460. * Solve factorial (!)
  461. *
  462. * Will take any real positive number and solve for it's factorial. Eg.
  463. * `5!` will become `1*2*3*4*5` = `120` For integers
  464. * and
  465. * 5.2! will become gamma(6.2) for non-integers
  466. * DONE:
  467. * Solve for non-integer factorials 2015/07/02
  468. *
  469. * @param Float $num Non-negative real number to get factorial of
  470. * @throws Exception if number is at or less than 0
  471. * @return Float Solved factorial
  472. */
  473. protected function factorial($num) {
  474. if($num < 0) {
  475. throw new Exception("Factorial Error: Factorials don't exist for numbers < 0", NF_EOS_Parser::E_NAN);
  476. }
  477. //A non-integer! Gamma that sucker up!
  478. if(intval($num) != $num) {
  479. return $this->gamma($num + 1);
  480. }
  481. $tot = 1;
  482. for($i=1;$i<=$num;$i++) {
  483. $tot *= $i;
  484. }
  485. return $tot;
  486. } //end function factorial
  487. /**
  488. * Gamma Function
  489. *
  490. * Because we can. This function exists as a catch-all for different
  491. * numerical approx. of gamma if I decide to add any past Lanczos'.
  492. * This method is public because a function doesn't currently exist
  493. * within this parser to use it. That will change in the future.
  494. *
  495. * @param $z Number to compute gamma from
  496. * @return Float The gamma (hopefully, I'll test it after writing the code)
  497. */
  498. public function gamma($z)
  499. {
  500. return $this->laGamma($z);
  501. }
  502. /**
  503. * Lanczos Approximation
  504. *
  505. * The Lanczos Approximation method of finding gamma values
  506. *
  507. * @link http://www.rskey.org/CMS/index.php/the-library/11
  508. * @link http://algolist.manual.ru/maths/count_fast/gamma_function.php
  509. * @link https://en.wikipedia.org/wiki/Lanczos_approximation
  510. * @param float $z Number to obtain the gamma of
  511. * @return float Gamma of inputted number
  512. * @throws Exception if Number is less than or equal to 0
  513. */
  514. protected function laGamma($z)
  515. {
  516. //check validity of $z, throw error if not a valid number to be used with gamma
  517. if($z <= 0) {
  518. throw new Exception("Gamma cannot be calculated on numbers less than or equal to 0", NF_EOS_Parser::E_NAN);
  519. }
  520. // Set up coefficients
  521. $p = array(
  522. 0 => 1.000000000190015,
  523. 1 => 76.18009172947146,
  524. 2 => -86.50532032941677,
  525. 3 => 24.01409824083091,
  526. 4 => -1.231739572450155,
  527. 5 => 1.208650973866179E-3,
  528. 6 => -5.395239384953E-6
  529. );
  530. //formula:
  531. // ((sqrt(2pi)/z)(p[0]+sum(p[n]/(z+n), 1, 6)))(z+5.5)^(z+0.5)*e^(-(z+5.5))
  532. // Break it down now...
  533. $g1 = sqrt(2*pi())/$z;
  534. //Next comes our summation
  535. $g2 =0;
  536. for($n=1;$n<=6;$n++) {
  537. $g2 += $p[$n]/($z+$n);
  538. }
  539. // Don't forget to add p[0] to it...
  540. $g2 += $p[0];
  541. $g3 = pow($z+5.5, $z + .5);
  542. $g4 = exp(-($z+5.5));
  543. //now just multiply them all together
  544. $gamma = $g1 * $g2 * $g3 * $g4;
  545. return $gamma;
  546. }
  547. } //end class 'Parser'