编写一个“解决”方程式的函数

时间:2013-05-08 19:34:36

标签: javascript math

我想编写一个函数,允许我在js中“求解”一个等式。

我想要的(不是编程语言):

function f(x) { 1 + x * x }
var z = 2
var y = f(z)  //y will be 5 as a number

我在JS写的:

function P(cfg) { ....
this.equation = "1 + x";
....};
P.prototype.eqn = function(x) {
    var tmp = eval(this.equation);
    return tmp;
};
....
P.prototype.draw = function() {....
for(var i = 0; i < z; i++)
    ctx.lineTo(i, this.eqn(i));
....};

我也读到在循环中使用eval可能不是一个好主意,但我还没有想出另一种方式(尚未)(JS初学者)......

此代码的问题是,至少在FF中,var tmp将STILL包含来自this.equation的字符串而不是计算值。

我非常感谢任何进一步的见解!

感谢您的时间:)

编辑:因为我的问题没有很好地阐述: 行执行后     var tmp = eval(this.equation); var tmp将保存一个STRING,它等于字符串this.equation,而不是所需的解y值。 此外,我并不是要解决,而是评估,谢谢你的提示:)

6 个答案:

答案 0 :(得分:4)

根据你的例子,我会说你要“评估一个表达式”,而不是“解决方程式”。要评估表达式,您可能会找到many tutorials。我会简短地分解一下。你需要做几个步骤。

从字符串“1 + x * x”开始,您需要将其分解为标记。具体而言,将其分解为:"1", "+", "x", "*", "x"。此时,您可以将变量(“x”)替换为其文字值(“2”),为您提供"1", "+", "2", "*", "2"

现在你需要解析表达式。基于order of operations PEMDAS,您需要创建一个树数据结构,其中首先执行括号子句(括号括起来的东西),然后执行乘法和除法,然后是加法和减法。解析通常不是一件容易的事,你可能想要将更简单的BNF语法放在一起(尽管你可以通过一些谷歌搜索来找到简单数学表达式的语法)。

接下来,首先走到树的深处,然后在树上进行评估操作。一旦到达树顶,就可以得到解决方案。

如果你想要“解决方程式”,那么你需要更复杂的东西,比如Sage

答案 1 :(得分:3)

我之前使用过this expression evaluator。它似乎工作得很好。它允许您将表达式传递给Parser,该Parser返回一个函数对象,然后可以评估输入。

var expr = Parser.parse("2 ^ x");
expr.evaluate({ x: 3 }); // 8

它支持trig函数(sin,cos,ect ...)和其他方便的内置函数,如abs和amp; CIEL。

var expr = Parser.parse("sin(x/2) + cos(x/2)")
expr.evaluate({x: Math.PI / 2}); // 1

示例:http://silentmatt.com/javascript-expression-evaluator/

代码:https://github.com/silentmatt/js-expression-eval

请注意,此lib不使用eval()。

答案 2 :(得分:2)

不确定我完全理解你的问题,但是如何:

var makeFunctionOfX = function(src) { 
    return Function('x', 'return ' + src); 
};

然后你可以这样说:

var g = makeFunctionOfX('2 * x')

var y = g(3); // y contains 6

这比eval的巨大优势在于我们创建的Function没有神奇的能力来查看范围中的变量(因此需要明确地将其作为参数传递x名称)。

答案 3 :(得分:2)

如果您信任用户的输入,使用eval是安全的,并且工作得很好。 (我不知道你的意思是什么“var tmp仍然会有字符串this.equation”。)

function FuncCreator(eqn){ this.eqn = eqn }
FuncCreator.prototype.run = function(x,y,z){ return eval(this.eqn) }

var add1 = new FuncCreator('1+x');
var result = add1.run(41); // 42

var complex = new FuncCreator('Math.sin(x*y) / Math.cos(z)');
var result = complex.run(3,4,5); // -1.891591285331882

如果您不信任用户输入,则需要实际解析输入并自行处理。这不重要。

答案 4 :(得分:2)

您可以使用math.js库中的表达式解析器,并执行以下操作:

var parser = math.parser();
var f = parser.eval('function f(x) = 1 + x * x');

// use the created function f in expressions:
parser.eval('z = 2');    // 2
parser.eval('y = f(z)'); // 5

// or use the created function f in JavaScript:
var z = 2;               // 2
var y = f(z);            // 5

在math.js中创建函数目前是有限的,尚不支持定义更广泛函数所需的循环和块。

答案 5 :(得分:0)

这是一个老线程,但我写了这个方程计算器,但这并不能解决代数方程。但是有一个函数可以让你提供一个包含赋值变量的数组。但这并不能解决没有指定值的变量。

我可能没有对每个测试用例场景进行置换,但它似乎工作得相当不错。

编辑:必须修改这个以处理负数。除此之外...工作正常。

Here is a fiddle

<!doctype html>
<html>
    <head>
        <title>Javascript Equation Calculator</title>
    </head>

    <body>
        <input type="button" onclick="main()" value="calculate"><br>
        <input type="text" id="userinput"><br>
        <span id="result">Ready.</span><br>
        <script>
            function Calculator(){}
            String.prototype.replaceLast = function (what, replacement)
            {
                var pcs = this.split(what);
                var lastPc = pcs.pop();
                return pcs.join(what) + replacement + lastPc;
            };
            function inS(substr, str){return (str.indexOf(substr) > -1);}
            function arrayValueOrToken(arr, key, token)
            {
                if(key in arr)
                {
                    return arr[key];
                }
                return token;
            }
            function reduceEquation(inputStr)
            {
                console.log("reduceEquation Executed-----");
                while(hasNest(inputStr))
                {
                    if(hasNest(inputStr))
                    {
                        inputStr = inputStr.replace(")(",')*(');
                        for(var i=0;i<=9;i++)
                        {
                            inputStr = inputStr.replace(i+"(",i+'*(');
                            inputStr = inputStr.replace(")"+i,')*'+i);
                        }
                        var s = inputStr.lastIndexOf("(");
                        var e =  0;
                        for(i=s;i,inputStr.length;i++){if(inputStr[i]==")"){e=i+1;break;}}
                        var eq = inputStr.substring(s,e);
                        var replace = eq;
                        eq = eq.replace(/[()]/g, '');
                        var substitution = solveEquation(eq);
                        inputStr = inputStr.replaceLast(replace,substitution);
                    }
                }
                return inputStr;
            }
            function solveEquation(eq)
            {
                console.log("solveEquation Executed-----");
                eq = doFirstOrder(eq);
                eq = doLastOrder(eq);
                return eq;
            }
            function doFirstOrder(eq)
            {
                console.log("doFirstOrder Executed-----");
                for(var i=0;i<eq.length;i++)
                {
                    if(eq[i]=="*"){eq = solve(eq,"*");return doFirstOrder(eq);}
                    if(eq[i]=='/'){eq = solve(eq,'/');return doFirstOrder(eq);}
                }
                return eq;
            }
            function doLastOrder(eq)
            {
                console.log("doLastOrder Executed-----");
                for(var i=0;i<eq.length;i++)
                {
                    if(eq[i]=="+"){eq = solve(eq,"+");return doLastOrder(eq);}
                    if(eq[i]=="-"){eq = solve(eq,"-");return doLastOrder(eq);}
                }
                return eq;
            }
            function solve(eq, operator)
            {
                var setOp = operator;
                console.log("solve Executed-----");
                var buildEq = "",var1 = true,done = false,char="";
                var operators = "+-/*";
                var ops = operators.replace(operator, '').split('');
                var a=ops[0];
                var b=ops[1];
                var c=ops[2];
                for(var i=0;i<eq.length;i++)
                {
                    char = eq[i];
                    switch(true)
                    {
                        case(char==operator):if(var1===true){var1 = false;}else{done = true;}break;
                        case(char==a):
                        case(char==b):
                        case(char==c):if(var1){char = ""; buildEq = "";}else{done = true;}
                    }
                    if(done){break;}
                    buildEq = buildEq + char;
                }
                var parts = parts = buildEq.split(operator);
                var solution = null;
                if(operator=="+"){solution = parseFloat(parts[0]) + parseFloat(parts[1]);}
                if(operator=="-"){solution = parseFloat(parts[0]) - parseFloat(parts[1]);}
                if(operator=="*"){solution = parseFloat(parts[0]) * parseFloat(parts[1]);}
                if(operator=="/"){solution = parseFloat(parts[0]) / parseFloat(parts[1]);}
                return eq.replace(buildEq, solution);
            }
            function hasNest(inputStr){return inS("(",inputStr);}
            function allNestsComplete(inputStr)
            {
                var oC = 0, cC = 0,char="";
                for(var i=0;i<inputStr.length;i++){char = inputStr[i];if(char=="("){oC+=1;}if(char==")"){cC+=1;}}
                return (oC==cC);
            }
            Calculator.prototype.calc = function(inputStr)
            {
                console.log("Calc Executed-----");
                inputStr = inputStr.replace(/ /g, "");
                inputStr = inputStr.replace(/\\/g, '/');
                inputStr = inputStr.replace(/x/g, "*")
                inputStr = inputStr.replace(/X/g, "*")
                if(!allNestsComplete(inputStr)){return "Nested operations not opened/closed properly.";}
                inputStr=reduceEquation(inputStr);
                inputStr = solveEquation(inputStr);
                return inputStr;
            };
            Calculator.prototype.calcWithVars = function(inputList)
            {
                if(inputList.length < 2){return "One or more missing arguments!";}
                var vars = [];
                var assocVars = [];
                var lastVarIndex = inputList.length - 2;
                var i = 0;
                var inputStr = inputList[inputList.length-1];
                for(i=0;i<=lastVarIndex;i++)
                {
                    vars.push(inputList[i].replace(/ /g, ""));
                }
                for(i=0;i<=vars.length-1;i++)
                {
                    var vParts = vars[i].split("=");
                    var vName = vParts[0];
                    var vValue = vParts[1];
                    assocVars[vName] = vValue;
                }
                inputStr = inputStr.replace(/ /g, "");
                var eqVars = inputStr.replace(/\s+/g, ' ').replace(/[^a-zA-Z-]/g, ' ').replace(/\s\s+/g, ' ');
                if(inS(" ", eqVars))
                {
                    eqVars = eqVars.split(" ");
                }
                else{eqVars = [eqVars];}
                eqVars.sort(function(a, b){return a.length - a.length;});
                var tempTokens = [];
                var tempCount = 1;
                for(i=0;i<eqVars.length;i++)
                {
                    var eqVname = eqVars[i];
                    var substitution = arrayValueOrToken(assocVars, eqVname, "<unknown>");
                    if(substitution != "<unknown>")
                    {
                        inputStr = inputStr.replace(eqVname,substitution);
                    }
                    else
                    {
                        var tempToken = "#______#"+tempCount+"#______#";
                        tempCount++;
                        tempTokens.push(tempToken + "?" + eqVname);
                        inputStr = inputStr.replace(eqVname,tempToken);
                    }
                }
                for(i=0;i<tempTokens.length;i++)
                {
                    var tokenSet = tempTokens[i];
                    var tokenParts = tokenSet.split("?");
                    var token = tokenParts[0];
                    var variableName = tokenParts[1];
                    inputStr = inputStr.replace(token,variableName);
                }
                var answerName = "<unknown>";
                var eq = inputStr;
                if(inS("=", inputStr))
                {
                    var eqParts = inputStr.split("=");
                    answerName = eqParts[0];
                    eq = eqParts[1];
                }
                eq = this.calc(eq);
                var result = [];
                for(i=0;i<eqVars.length;i++)
                {
                    var v = arrayValueOrToken(assocVars, eqVars[i], "<unknown>");
                    if(v != "<unknown>")
                    {
                        result.push(assocVars[eqVars[i]]);
                    }
                }
                result.push(eq);
                return result;
            };
            function main()
            {
              var calculator = new Calculator();
              elUserInput = document.getElementById('userinput');
              console.log("input: "+ elUserInput.value);
              elResult = document.getElementById('result');
              equation = elUserInput.value;
              result = calculator.calc(equation);
              console.log("result: "+ result);
              elResult.innerHTML = result;
            }
        </script>
    </body>
</html>