Scripts for Dr. Math Graphs & Charts Scripts

Dr. Math is a PHP class that helps you with important mathematical functions: – Equation solver – Function plotter.

 

<?php

class math {

/************************************************************************************
*  Copyright notice
*
*  Dr. Mathe
*
*  Copyright (C) 2000-2005 CH Software (info@chsoftware.net)
*  www.chsoftware.net
*  All rights reserved
*  For more information go to:
*  www.chsoftware.net/en/useware/conditions/conditions.htm
*
*
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*  The GNU General Public License can be found at
*  http://www.gnu.org/licenses/gpl.html
*  A copy is found in the textfile GPL.txt and important notices to the license
*  from the author is found in LICENSE.txt distributed with these scripts.
*
*************************************************************************************/


/** Class for some math functions
 *
 *  This class allows you, to use some special math functions, eg. solving easy equations or drawing a graph
 *
 *  Revised on 10/5/2004 (de: 5.10.2004) by Cornelius Herzog
 *
 *  @author    Cornelius Herzog (c.herzog@chsoftware.net)
 *
 */


 /**
 * Settings for the program parts
 */


 /** Settings for the solver **/
 var $maxbound = 1000;                     //maximal number for intervalcalculation
 var $minbound = -1000;                    //minimal number for intervalcalculation
 var $debug_output = FALSE;                //debug output (max, min, middle, result)
 var $max_iterations = 100000;                 //maximum number of interations
 var $start_value = 0;                    //startvalue of the middle
 var $intelligent_search = TRUE;            //Use the intelligent search?
 var $return_human = TRUE;



 /**
 * General vars
 */

 var $done_iterations;                     //returns the number of done equations
 var $parsed_term;                        //contains the last parsed term

 /**
 * Allowed functions. All other commands are filtered of
 */

 var $allowed_commands = array("abs(#)","acos(#)","asin(#)","atan(#)","atan2(#,#)","base_convert(#,#,#)","bindec(#)","ceil(#)","cos(#)","decbin(#)","dechex(#)","decoct(#)","deg2rad(#)","exp(#)","floor(#)","hexdec(#)","log(#)","log10(#)","octdec(#)","pi","pow(#,#)","rad2deg(#)","rand(#,#)","round(#,#)","sin(#)","sqrt(#)","tan(#)");


 /**
 * Solve an equation
 *
 * @param    eq         string            equation term
 * @param     var        string            name of the var by the term should be solved
 * @return    result
 */

 function solve($eq,$var) {
 if(!$eq OR !$var) { $this->errorhandler(2,"solve"); }
 if(!stristr($eq,"=")) {
 $this->errorhandler(1);
 }
 $t = explode("=",$eq);
 $l = trim($t[0]);
 $r = trim($t[1]);
 $l = $this->parse_term($l);
 $r = $this->parse_term($r);
 if(stristr($l,$var) AND stristr($r,$var)) {
 $term = $l . "-(" . $r . ")";
 $sol = $this->intervalapprox($term,0,$var);
 }elseif((stristr($l,$var) AND !stristr($r,$var)) OR (!stristr($l,$var) AND stristr($r,$var))) {
 if(stristr($l,$var)) {
 $sol = $this->intervalapprox($l,$r,$var);
 }else{
 $sol = $this->intervalapprox($r,$l,$var);
 }
 }elseif(!stristr($l,$var) AND !stristr($r,$var)) {#
if($l == $r) {
 return "Infinite solutions";
 }else{
 return "No solution";
 }
 }else{
 errorhandler(3,$eq);
 }
 if($this->return_human == TRUE and stristr($sol,".")) {
 $soln = $this->square2dec($sol);
 if($soln == $sol) {
 $sol = $this->dec2frac($sol);
 }else{
 $sol = $soln;
 }
 return $sol;
 }else{
 return $sol;
 }
 }

 /**
 * Do an interval approximation
 *
 * @param    expr    string            equation term
 * @param     val        string            value the terme must be
 * @param     var        string            name of the var by the term should be solved
 * @return    result
 */

 function intervalapprox($expr,$val,$var) {
 $expr = strip_tags($expr);
 $expr = "\$res = " . $expr .";";
 $max = $this->maxbound;
 $min = $this->minbound;
 $count = 0;
 $middle = $this->start_value;
 while($sol == "") {
 $$var = $middle;
 eval($expr);
 if($this->debug_output == TRUE) {
 echo "Max: $max <br> Min: $min <br> Middle: $middle <br>Result: $res<hr>";
 }
 if($this->intelligent_search == TRUE) {
 if(round($res,10) == $val) {
 $this->done_iterations = $count;
 return round($middle,10);
 }else{
 $isol = $this->intelligent_search($expr,$val,$var,$middle);
 if(strlen($isol) != 0) {
 $this->done_iterations = $count;
 return round($middle,$isol);
 }
 }
 }else{
 if(round($res,10) == $val) {
 $this->done_iterations = $count;
 return round($middle,10);
 }
 }

 if($res > $val) {
 $max = $middle;
 }
 if($res < $val) {
 $min = $middle;
 }
 $middle = ($max + $min) / 2;
 $count++;
 if($count == $this->max_iterations) { $this->errorhandler("4"); return ""; }
 }
 }

 /**
 * Makes a rooted decimal number to his root
 *
 * @param    n        double            input number
 * @return    double
 */

 function square2dec($n) {
 if(!stristr(round($n * $n,2),".")) {
 return "sqr(" . round($n * $n,2) . ")";
 }else{
 return $n;
 }
 }


 /**
 * Do an intelligent check of the given number in the equ
 *
 * @param    expr        string            equation term
 * @param    val            double            the result that must come out
 * @param     var            string            the function variable
 * @param    testval        double            the value to test with
 * @return    double                    solution
 */


 function intelligent_search($expr,$val,$var,$testval) {
 $$var = $testval;
 eval($expr);
 if($res == $val) { return 0;}
 if(stristr($testval,".")) {
 for($rstellen=10;$rstellen>=0;$rstellen--) {
 $test = round($testval,$rstellen);
 $$var = $test;
 eval($expr);
 if($res == $val) {    return $rstellen;}
 }
 }else{
 $$var = $testval;
 eval($expr);
 if($res == $val) { return 0;}
 }
 return "";
 }

 /**
 * Makes a term readable for the interpreter
 *
 * @param    expr    string            equation term
 * @return    string
 * @return this->parsed_term, string
 */

 function parse_term($t) {
 $t = strip_tags($t);                            //remove tags, prevent cross scripting
 $t = strtolower($t);                            //all to lower case
 $nropen = substr_count($t,"(");                    //check if the number of brackets is the same
 $nrclose = substr_count($t,")");
 if($nropen != $nrclose) {
 $arg[0] = $nropen;
 $arg[1] = $nrclose;
 $this->errorhandler("5",$arg);
 }
 for($x=0;$x<strlen($t);$x++) {                    //run for all chars
 $pc = $t[$x-1];                                //previous char of the actual
 $tc = $t[$x];                                //actual char
 $nc = $t[$x+1];                                //next char
 if(!$this->is_number($tc)) {                //just parse if this char is not a number
 //many if conditions weight out what to do, no comments.
 if(($this->is_number($nc) || !$this->is_char($nc)) &amp;&amp; !$this->is_char($pc) &amp;&amp; !$this->is_operator($tc) &amp;&amp; $pc != "\$") {
 $t = $this->prefix($t,$x,"\$");
 }
 if($tc == "(" and $this->is_number($pc)) {
 $t = $this->prefix($t,$x,"*");
 }
 if($this->is_number($pc) &amp;&amp; ($tc == "\$" || $this->is_char($tc))) {
 $t = $this->prefix($t,$x,"*");
 }
 if($this->is_char($tc) &amp;&amp; $pc == ")") {
 $t = $this->prefix($t,$x,"*");
 }
 if($tc == ")" &amp;&amp; $this->is_char($pc) &amp;&amp; $t[$x-2] == "(") {
 $t = $this->prefix($t,$x-1,"\$");
 }
 //checks if we have a function in the term as if cos, sin or sth like that
 for($y=0;$y<sizeof($this->allowed_commands);$y++) {
 if($tc . $nc == substr($this->allowed_commands[$y],0,2)) {
 $tmp = explode("(",$this->allowed_commands[$y]);
 $cmdlen = strlen($tmp[0]);
 $cmdrest = substr($t,$x);
 $endcmd = strpos($cmdrest,")") + 1;
 $fullcmd = substr($cmdrest,0,$endcmd);
 $n_args = substr_count($this->allowed_commands[$y],"#");
 $g_args = substr_count($fullcmd,",") + 1;
 if($n_args != $g_args) {
 $this->errorhandler(2,'"'.$tmp[0].'". You gave '.$g_args.' argument(s) but there is needed '.$n_args.' argument(s)');
 }
 $x = $x + $cmdlen + 1;
 }
 }
 }
 }
 $t = str_replace(")\$",")*\$",$t);            //add a * between a bracket and a variable
 $t = str_replace(")(",")*(",$t);            //add a * between two brackets

 //fixes the bug, that there is no * between a number an a closing bracket
 for($x=0;$x<strlen($t);$x++) {
 $pc = $t[$x-1];
 $tc = $t[$x];
 $nc = $t[$x+1];
 if($this->is_number($tc) &amp;&amp; $pc == ")") {
 $t = $this->prefix($t,$x,"*");
 }
 }
 //this for statement makes the exponents working, because php doesn't know ^. eg (x-2)^2 = (x-2)*(x-2)
 for($x=0;$x<strlen($t);$x++) {
 $pc = $t[$x-1];
 $tc = $t[$x];
 $nc = $t[$x+1];
 if($tc == "^") {
 $i=1;
 while($this->is_number($t[$x+$i])) {
 $i++;
 }
 $ex = str_replace("^","",substr($t,$x,$i));
 if($this->is_char($pc) &amp;&amp; $t[$x-2] == "\$") {
 $pattern = substr($t,$x-2,2);
 $nex = $this->pattern_repeater($pattern,"*",$ex);
 $t = str_replace($pattern . "^" . $ex,$nex,$t);
 }elseif($pc == ")") {
 $tmpstr = substr($t,0,$x);
 $cb = 0;
 $ob = 0;
 for($k=strlen($tmpstr)-1;$k>=0;$k--) {
 if($tmpstr[$k] == ")") {
 $cb++;
 }
 if($tmpstr[$k] == "(") {
 $ob++;
 }
 if($ob != 0 &amp;&amp; $cb != 0 &amp;&amp; $cb == $ob) {
 $pos = $k;
 break;
 }
 }
 $pattern = substr($tmpstr,$pos);
 if($this->is_char($prepos) AND $pprepos == "\$") {
 $pattern = substr($tmpstr,$pos);
 $nex = $this->pattern_repeater($pattern,"*",$ex);
 $t = str_replace($pattern . "^" . $ex,$nex,$t);
 }else{
 $i=1;
 if($z == 1) { echo $tmpstr . "<br>"; }
 while($this->is_char($t[$pos-$i])) {
 $i++;
 }
 $pattern = substr($tmpstr,$pos-$i+1);
 $bopencount = substr_count($pattern,"(");
 $bclosecount = substr_count($pattern,")");
 if($bopencount != $bclosecount) {
 $pattern = "(" . $pattern;
 }
 $nex = $this->pattern_repeater($pattern,"*",$ex);
 $t = str_replace($pattern . "^" . $ex,$nex,$t);
 }
 }elseif($this->is_number($pc)) {
 $tmpstr = substr($t,0,$x);
 $i=1;
 while($this->is_number($t[$x-$i])) {
 $i++;
 }
 $pattern = substr($tmpstr,-$i+1);
 $nex = $this->pattern_repeater($pattern,"*",$ex);
 $t = str_replace($pattern . "^" . $ex,$nex,$t);
 }
 }
 }
 $this->parsed_term = $t;
 return $t;
 }


 /**
 * Repeats a pattern x times
 *
 * @param    pattern        string            the pattern to repeat
 * @param     glue        string            glue the pattern with this string
 * @param     nr            double            number of repeating the pattern
 * @return    string
 */

 function pattern_repeater($pattern,$glue,$nr) {
 for($i=0;$i<$nr;$i++) {
 $str.= $pattern . $glue;
 }
 if(substr($str,-1) == $glue) { $str = substr($str,0,-1); }
 return $str;
 }

 /**
 * Prefix a char in a string with a char or string
 *
 * @param    str        string            input string
 * @param     pos        double
 * @return    string
 */

 function prefix($str,$pos,$prefix) {
 $v = substr($str,0,$pos);
 $h = substr($str,$pos);
 $str = $v . $prefix . $h;
 return $str;
 }

 /**
 * Check if the given char is an operator
 *
 * @param    n        char            input char to check
 * @return    boolean
 */

 function is_operator($n) {
 if($n == "+" || $n == "-" || $n == "*" || $n == "/" || $n == "^" || $n == "(" || $n == ")") {
 return true;
 }else{
 return false;
 }
 }

 /**
 * Check if the given char is a char
 *
 * @param    n        char            input char to check
 * @return    boolean
 */

 function is_char($n) {
 $v = ord($n);
 if(97 <= $v &amp;&amp; 122 >= $v) {
 return true;
 }else{
 return false;
 }
 }

 /**
 * Check if the given char is a number
 *
 * @param    n        char            input char to check
 * @return    boolean
 */

 function is_number($n) {
 $v = ord($n);
 if((48 <= $v &amp;&amp; 57 >= $v) || $n == ".") {
 return true;
 }else{
 return false;
 }

 }

 /**
 * Convert a decimal number to a fraction
 *
 * @param    n    double        number
 * @return    fraction
 */



 function dec2frac($n,$format = "total") {
 $n = str_replace(",",".",$n);
 $t = explode(".",$n);
 $full = $t[0];
 $part = $t[1];
 if($format == "total") {
 $zaehler = str_replace(".","",$n);
 if(substr($zaehler,0,1) == "0") { $zaehler = substr($zaehler,1); }
 $nenner = "1";
 $nenner = str_pad($nenner, strlen($part)+1,"0");
 $gcd = $this->gcd($zaehler,$nenner);
 if($gcd != "") {
 $zaehler = $zaehler / $gcd;
 $nenner = $nenner / $gcd;
 }
 return $zaehler . "/" . $nenner;
 }else{
 $zaehler = $part;
 $nenner = "1";
 $nenner = str_pad($nenner, strlen($part)+1,"0");
 $gcd = $this->gcd($zaehler,$nenner);
 if($gcd != "") {
 $zaehler = $zaehler / $gcd;
 $nenner = $nenner / $gcd;
 }
 return $full . " " . $zaehler . "/" . $nenner;
 }

 }

 /**
 * get the greatest common divisor of two numbers
 *
 * @param    v1    double        number 1
 * @param    v2    double        number 2
 * @return    gcd
 */


 function gcd($v1,$v2)  {
 do {
 $d = $v1 % $v2;
 if($d == 0) { return $v2;  }
 $v1 = $v2;
 $v2 = $d;
 } while($d != 0);
 }


 function errorhandler($errnr,$i = "") {
 switch($errnr) {
 case 1:
 $err = "Missing =. Can't proceed";
 $p = false;
 break;
 case 2:
 $err = "Not the right number of arguments for function $i. Can't proceed.";
 $p = false;
 break;

 case 3:
 $err = "Unknow type of equation. Can't proceed";
 $p = false;
 break;
 case 4:
 $err = "No solution found for the given equation";
 $p = true;
 break;
 case 5:
 $err = "Not the same number of brackets. You have ".$i[0] . " opening bracket(s) and ".$i[1] ." closing bracket(s)!";
 break;
 case 6:
 $err = "The term $i could not be parsed. Please check it for errors!";
 $p = true;
 break;
 }
 echo '<div style="font-family: Verdana; font-size: 10pt; font-weight:bold; color:red; background-color:lightblue;">'.$err.'</div>';
 if($p == false) {
 die();
 }
 }


}




?>

&amp;nbsp;

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>