我想编写一个函数,允许我在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值。 此外,我并不是要解决,而是评估,谢谢你的提示:)
答案 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)
这是一个老线程,但我写了这个方程计算器,但这并不能解决代数方程。但是有一个函数可以让你提供一个包含赋值变量的数组。但这并不能解决没有指定值的变量。
我可能没有对每个测试用例场景进行置换,但它似乎工作得相当不错。
编辑:必须修改这个以处理负数。除此之外...工作正常。
<!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>