
/* ****************************************************************** */
/*                compute() by Allen Murphy 01/05/07                  */
/* ****************************************************************** */
function compute(funct, value) {
	/* This function takes a math function expression and evaluates it for
	   the given value.  It returns the value of the function. */

	var result = 0;

	/* Create a parser object */	
	var parser = new MathProcessor();
	
	/* Create expression srting */
	var e = funct.replace("pi", Math.PI);

	/* Create the value to the nearest thousandth */	
	var x = 0;
	x = Math.round(value*1000)/1000;
	
	/* Expression house keeping to avoid mistaking exp for x */
	e = e.toLowerCase();
	e = e.replace(" ", "");
	e = e.replace("exp", "EXP");

	/* Substitute x value */
	e = e.replace("x", x);
	e = e.replace("EXP", "exp");
	
	try {
		result = parser.parse(e);
	}
	catch(error) {
		result = 0;
		window.document.getElementById("myOutput").innerHTML = error;
	}
	return result;
}

/* ****************************************************************** */
//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/classes/math-processor [v1.0]
/* ****************************************************************** */
MathProcessor = function(){ //v1.0
    var o = this;
    o.o = {
        "+": function(a, b){ return +a + b; },
        "-": function(a, b){ return a - b; },
        "%": function(a, b){ return a % b; },
        "/": function(a, b){ return a / b; },
        "*": function(a, b){ return a * b; },
        "^": function(a, b){ return Math.pow(a, b); },
        "~": function(a, b){ return Math.sqrt(a, b); }
    };
    o.s = { "^": 3, "~": 3, "*": 2, "/": 2, "%": 1, "+": 0, "-": 0 };
    o.u = {"+": 1, "-": -1}, o.p = {"(": 1, ")": -1};
};

/* ****************************************************************** */
MathProcessor.prototype.parse = function(e){
    for(var n, x, o = [], s = [x = this.RPN(e.replace(/ /g, "").split(""))]; s.length;)
        for((n = s[s.length-1], --s.length); n[2]; o[o.length] = n, s[s.length] = n[3], n = n[2]);
    for(; (n = o.pop()) != undefined; n[0] = this.o[n[0]](isNaN(n[2][0]) ? this.f(n[2][0]) : n[2][0], isNaN(n[3][0]) ? this.f(n[3][0]) : n[3][0]));
    return +x[0];
};

/* ****************************************************************** */
MathProcessor.prototype.methods = {
    "div": function(a, b){ return parseInt(a / b); },
    "frac": function(a){ return a - parseInt(a); },
    "sum": function(n1, n2, n3, n){ for(var r = 0, a, l = (a = arguments).length; l; r += a[--l]); return r; },
    "avg": function(a, b){ return (a + b) / 2; },
    "sqrt": function(a){ return Math.sqrt(a); },
    "sin": function(a){ return Math.sin(a); },
    "cos": function(a){ return Math.cos(a); },
    "tan": function(a){ return Math.tan(a); },
    "ln": function(a){ return Math.log(a); },
    "abs": function(a){ return Math.abs(a); },
    "asin": function(a){ return Math.asin(a); },
    "acos": function(a){ return Math.acos(a); },
    "atan": function(a){ return Math.atan(a); },
    "atan2": function(a){ return Math.atan2(a); },
    "exp": function(a){ return Math.exp(a); },
    "ceil": function(a){ return Math.ceil(a); },
    "floor": function(a){ return Math.floor(a); },
    "max": function(a,b){ return Math.max(a,b); },
    "min": function(a,b){ return Math.min(a,b); },
    "round": function(a){ return Math.round(a,b); },
};

/* ****************************************************************** */
MathProcessor.prototype.error = function(s){
    throw new Error("MathProcessor: " + s + " - Error in expression.");
}

/* ****************************************************************** */
MathProcessor.prototype.RPN = function(e){
    var _, r, c = r = [, , , 0];
    if(e[0] in this.u || !e.unshift("+"))
        for(; e[1] in this.u; e[0] = this.u[e.shift()] * this.u[e[0]] + 1 ? "+" : "-");
    (c[3] = [this.u[e.shift()], c, , 0])[1][0] = "*", (r = [, , c, 0])[2][1] = r;
    (c[2] = this.v(e))[1] = c;
    (!e.length && (r = c)) || (e[0] in this.s && ((c = r)[0] = e.shift(), !e.length && this.error()));
     while(e.length){
        if(e[0] in this.u){
            for(; e[1] in this.u; e[0] = this.u[e.shift()] * this.u[e[0]] + 1 ? "+" : "-");
            (c = c[3] = ["*", c, , 0])[2] = [-1, c, , 0];
        }
        (c[3] = this.v(e))[1] = c;
        e[0] in this.s && (c = this.s[e[0]] > this.s[c[0]] ?
            ((c[3] = (_ = c[3], c[2]))[1][2] = [e.shift(), c, _, 0])[2][1] = c[2]
            : r == c ? (r = [e.shift(), , c, 0])[2][1] = r
            : ((r[2] = (_ = r[2], [e.shift(), r, ,0]))[2] = _)[1] = r[2]);
    }
    return r;
};

/* ****************************************************************** */
MathProcessor.prototype.v = function(e){
    if("0123456789.".indexOf(e[0]) + 1){
        for(var i = -1, l = e.length; ++i < l && "0123456789.".indexOf(e[i]) + 1;);
        return [+e.splice(0,i).join(""), , , 0];
    }
    else if(e[0] == "("){
        for(var i = 0, l = e.length, j = 1; ++i < l && (e[i] in this.p && (j += this.p[e[i]]), j););
        return this.RPN(l = e.splice(0,i), l.shift(), !j && e.shift());
    }
    else{
        var i = 0, c = e[0].toLowerCase();
        if((c >= "a" && c <= "z") || c == "_"){
            while(((c = e[++i].toLowerCase()) >= "a" && c <= "z") || c == "_" || (c >= 0 && c <= 9));
            if(c == "("){
                for(var l = e.length, j = 1; ++i < l && (e[i] in this.p && (j += this.p[e[i]]), j););
                return [e.splice(0,i+1).join(""), , , 0];
            }
        }
    }
    this.error();
}

/* ****************************************************************** */
MathProcessor.prototype.f = function(e){
    var i = 0, n;
    if(((e = e.split(""))[i] >= "a" && e[i] <= "z") || e[i] == "_"){
        while((e[++i] >= "a" && e[i] <= "z") || e[i] == "_" || (e[i] >= 0 && e[i] <= 9));
        if(e[i] == "("){
            !this.methods[n = e.splice(0, i).join("")] && this.error("Função \"" + n + "\" não encontrada"), e.shift();
            for(var a = [], i = -1, j = 1; e[++i] && (e[i] in this.p && (j += this.p[e[i]]), j);)
                j == 1 && e[i] == "," && (a.push(this.parse(e.splice(0, i).join(""))), e.shift(), i = -1);
            a.push(this.parse(e.splice(0,i).join(""))), !j && e.shift();
        }
        return this.methods[n].apply(this, a);
    }
};


