比较数学表达式

时间:2013-01-27 12:05:56

标签: java algorithm parsing math floating-point

所以这是我的情况:我有两个包含变量(x,y,z等)的数学表达式。我已经使用shunting yard algorithm将它们编译为postfix,现在我需要一种方法来测试它们是否在数学上相等。

示例:

x+5==5+x
x*2==x+x
4/(x/2)==8/x

我最初的想法是抛出几千种不同的随机输入,看看评估结果是否相同。

我预见到这种方法存在的问题:精度问题,NaN情况和可能的溢出。

所有计算都是用Java的双重类型完成的。

有什么想法吗? :)

编辑:因为这是一款休闲游戏,解决方案不需要完美,只有足够好!

3 个答案:

答案 0 :(得分:5)

对于您提供的示例表达式,您可以将函数转换为生成一个除以另一个的多项式,其中除数的最大有效系数为1,并且没有公因子。这会给你一个规范的形式 - 如果存在差异,这两个函数真的会有所不同。但是,您还需要将系数表示为任意精度的有理数或在此处遇到精度问题,然后您将编写大部分基本计算机代数系统,例如http://en.wikipedia.org/wiki/List_of_computer_algebra_systems中列出的系统 - 其中包括一些免费系统。

答案 1 :(得分:4)

根据Wikipidea关于这个主题:

http://en.wikipedia.org/wiki/Symbolic_computation

“数学表达式有两种相等的概念。句法相等是表达式的相等,这意味着它们以相同的方式被写入(或在计算机中表示)。尽管如此,数学家很少考虑它们,但它是唯一容易用程序测试的相等。语义相等是当两个表达式代表相同的数学对象时,如

众所周知,如果表达式中允许使用指数和对数,则可能不存在决定表示数字的两个表达式在语义上是否相等的算法。因此,(语义)相等性只能在某些类表达式上进行测试,例如多项式和有理分数。

为了测试两个表达式的相等性,而不是设计一个特定的算法,通常将它们置于某种规范形式或将它们的差异置于正常形式并测试结果的句法相等性。“

这似乎是最好的做法。

答案 2 :(得分:2)

当我到达这里时,我试图写出基本相同的问题。但是我发现了一些在这里没有提到的想法。 首先,我同意@nelshh,在某些特定情况下,您可以找到允许测试表达式相等性的规范形式。

我找到了一些规范形式的例子:

  • 最着名的可能是布尔代数中的minterm canonical form,用于电路综合或验证。
  • 多项式表达式也承认规范形式为单项式的总和。这可以解决您的示例:
  • 有理数的规范形式是irreductible fraction

您的示例:

  1. 两者都已经是规范形式,你只需要通过提高程度来对它们进行排序。
  2. 2*x处于规范形式,x+x不是(因为添加的两个操作数都具有相同的度数)。
  3. 两者都已经是规范形式(度数为-1的单项式),除了4/(x/2)4/(1/2)的系数不是有理数的规范形式。
  4. 如果您仍对此感兴趣,我建议您尝试使用计算机代数系统,例如sympy for python(它可能也适用于java)。但是,我还认为您应该删除标记javafloating-point(它与计算机存储实数的方式无关),并添加标记computer-science

    例如,sympy可以说出这样的话:

    >>> Rational(3,4)*(x+y)**2
             2
    3⋅(x + y) 
    ──────────
        4     
    >>> Rational(3,4)*(x**2+y**2)+Rational(1,4)*2*x*y+Rational(4,8)*2*x*y
       2              2
    3⋅x    3⋅x⋅y   3⋅y 
    ──── + ───── + ────
     4       2      4  
    >>> expand(Rational(3,4)*(x+y)**2)==expand(Rational(3,4)*(x**2+y**2)+Rational(1,4)*2*x*y+Rational(4,8)*2*x*y)
    True