如何解析&在JavaScript计算器中处理数学表达式?

时间:2016-01-10 15:19:59

标签: javascript twitter-bootstrap

使用javascript评估3+1*sin(20)*e^3等表达式的最佳方法是什么?

首先,我不想使用内置的数学函数。事实上,我已经为powersquare rootsincosexponential等定义了自己的函数。

我正在寻找的是解析表达式的好方法,这样我就可以将它们传递给我创建的这些函数。我知道JavaScript中有一个eval()函数用于评估输入表达式,但我不确定它是否适用于此上下文。

我应该使用eval()吗?如果是,我如何在这种情况下使用它?如果不是,什么是解析数学表达式更合适的方法?! 这不是学校作业,只是一个疑问。

2 个答案:

答案 0 :(得分:2)

使用第三方库

在现实生活中,您希望使用像math.js这样的库来为您进行计算。

要使用此库,请先将其包含在HTML中:

 <script src='path/to/math.js'></script>

然后,您可以使用math.eval方法来评估您的表达式:

math.eval('3+1*sin(20)*e^3');

也就是说,如果20是以弧度表示的值。由于它可能是以度数表示的值,因此您需要进行这种小调整:

math.eval('3+1*sin(20 deg)*e^3');

因为您明确表示您不想使用内置的数学函数,我怀疑您正在从事学校作业。请注意,在StackOverflow上提交学校作业不赞成,因为它被视为作弊形式。

但是,让我们忽略这一点并继续前进,不管吗?!

自己动手

步骤1:使用内置数学函数进行计算

在现实生活中,您应该始终使用内置数学函数或第三方库(如math.js),这些库使用内置数学函数。这是因为内置数学函数100%可靠且性能优化。

以与内置函数一样可靠和性能优化的方式创建自己的内置数学函数是不可能的,所以没有充分的理由不使用内置功能。但是既然你明确地要求它,那就让我们忽略它,看看如何在没有内置数学函数的情况下做事。我认为这也暗示您不想使用math.js或任何其他库。

使用JavaScript的内置函数,您可以像这样计算表达式:

3+1*Math.sin(20)*Math.pow(Math.E,3)

使用内置函数:

在此,重要的是,只有当20是弧度值时,这才是正确的。因为20可能是度数的值,你可能想要定义你自己的基于度函数的sin函数,如下所示:

var dsin = function() {
  var piRatio = Math.PI / 180;
  return function dsin(degrees) {
    return Math.sin(degrees * piRatio);
  };
}();

现在,将Math.sin替换为dsin

3+1*dsin(20)*Math.pow(Math.E,3)

在任何实际应用中,最好是计算3+1*sin(20)*e^3

第2步:使用您自己的

替换内置数学函数

现在,正如你真的,真的,真的似乎想要没有内置函数,下一步就是用自编的等价替换每个内置函数。通常,有多条数学路径可以达到同一目标。

例如,您可以像这样递归地编写pow函数:

var pow = function(base, exp) {
  if (exp == 0)
    return 1;
  else
    return base * power(base, exp - 1);
}

迭代实施:

var pow = function(base, exp) {
  var result = 1;
  while(exp--) {
    result *= base;
  }
  return result;
}

所以现在,你问什么?!你问,如何在不依赖dsin的情况下实施Math.sin

嗯......一些研究告诉你,你可以使用公式sin计算sin(x) = x - x^3 / 3! + x^5 / 5! - x^7 / 7! + x^9 / 9! - ...

在JavaScript中,这将是这样的:

var sin = function(x) {
    var t1 = -1,t2 = 3,v1 = x,v2 = v1 + 1,it = 0;
    while (it < 10) {
        v2 = v1 + (t1 * pow(x, t2) / function(n){
        j = 1;
        for(i=1;i<=n;i++)
            j = j*i;
            return j;
        }(t2));
        t1 = -1 * t1;
        t2 += 2;
        v1 = v2;
        it++;
    }
    return v2;
}

您可能会注意到我将我的因子计算放在lambda函数中。一个更优雅的解决方案是将lambda函数放在一个单独的函数中,因为您可能在其他地方需要它。

现在,你只需要拼凑所有碎片并将它们包裹在一个漂亮的物体中:

var Calc = (function(){
    return {
        E : 2.718281828459045,
        pow : function (base, exp) {
            var result = 1;
            while (exp--) {
                result *= base;
            }
            return result;
        },
        fact : function(n){
            j = 1;
            for(i=1;i<=n;i++)
                j = j*i;
            return j;
        },
        sin : function(x) {
            var t1 = -1,t2 = 3,v1 = x,v2 = v1 + 1,it = 0;
            while (it < 10) {
                v2 = v1 + (t1 * this.pow(x, t2) / this.fact(t2));
                t1 = -1 * t1;
                t2 += 2;
                v1 = v2;
                it++;
            }
            return v2;
        },
        dsin : function() {
            var piRatio = Math.PI / 180;
            return function dsin(degrees) {
                return Math.sin(degrees * piRatio);
            };
        }()
    };
})();

您可以像这样使用这些对象的方法:

3+1*Calc.dsin(20)*Calc.pow(Calc.E,3)

第3步:解析

如果您确实希望应用程序直接读取3+1*sin(20)*e^3这样的表达式,则不应使用eval()。相反,你应该编写自己的解析器。

执行此操作的正确方法是首先编写将表达式转换为语法树的标记生成器。然后,将语法树传递给解释器,该解释器通过运行您在步骤1中创建的计算函数来处理语法树。

要深入了解如何构建语法树和解释器,您可以查看this tutorial

答案 1 :(得分:-3)

除了standard JavaScript math library之外,如果您还想要更多数学功能,那么您可能需要使用第三方库,例如math.js

要使用此库,请先将其包含在HTML中:

 <script src='path/to/math.js'></script>

然后,您可以使用math.eval方法来评估您的表达式:

math.eval('3+1*sin(20)*e^3');