Php 如何尽可能地简化数学公式
我会尽量客观地回答这个问题 我有一个数据库,其中包含应用程序创建的数百万个数学公式,这些公式符合逻辑: 1) 只涉及5个数学运算:加法、减法、乘法、除法和幂(+-*/^) 2) 每个操作都用括号分隔/分组 “参数”可以很简单,例如常量或变量 示例:(x+15) 在复合情况下,我可能有: (x*(x+15)) 重要的是要记住,使用括号可以保证正确的操作顺序 例如: ((x*(x+15))/15) 我的挑战是减少这些公式 当操作相同时,无论因素的顺序如何,它们都没有用处或重复很多次 例如: ((x+4)+8)-x)/12) 等于1,它不是一个公式,它是一个常数,我必须忽略它 像((x+4)+8)和((8+x)+4)这样的双重性需要消除 这就是为什么我需要减少 请注意,所有公式都使用括号和操作之间的空格进行标准化 我在PHP中创建了一个例程,使用正则表达式进行替换,我成功地在一个特定的公式中取得了巨大的进步,从8000种可能性减少到不到300种 然而,随着公式的大小(不是复杂性,因为它们并不复杂)的增加,我的例程不再有效 我需要一个算法,而不是例行程序,来应用我们在学校学到的数学简化 我认为这是可能的,因为公式是标准化的,并且只限于5个基本的数学运算 我正在使用GitHub中获得的EvalMath类来帮助简化和执行公式 为了让您更好地了解,这些公式是抽象的,每个“@”都会被常量和变量实时替换Php 如何尽可能地简化数学公式,php,math,formulas,Php,Math,Formulas,我会尽量客观地回答这个问题 我有一个数据库,其中包含应用程序创建的数百万个数学公式,这些公式符合逻辑: 1) 只涉及5个数学运算:加法、减法、乘法、除法和幂(+-*/^) 2) 每个操作都用括号分隔/分组 “参数”可以很简单,例如常量或变量 示例:(x+15) 在复合情况下,我可能有: (x*(x+15)) 重要的是要记住,使用括号可以保证正确的操作顺序 例如: ((x*(x+15))/15) 我的挑战是减少这些公式 当操作相同时,无论因素的顺序如何,它们都没有用处或重复很多次 例如: ((x+
(@ + @)
(@ / @)
(@ ** @)
((@ + @) + @)
((@ + @) ** @)
((@ - @) + @)
((@ - @) / @)
((@ - @) ** @)
((@ * @) + @)
((@ * @) / @)
((@ * @) ** @)
((@ / @) / @)
下面是一段PHP代码,它是我的简化例程的一部分
在一段时间内(没错),我将重复的规则分组,直到没有替换
最后,我得到了一个数组,其中包含许多重复项,这些重复项是通过对公式中的元素进行一些缩减和重新排序而获得的,这是数组_unique()解决的问题
我真的需要帮助,我的大脑因为这个问题而爆炸
多谢各位
<?php
$Math_Formulas = array(
'(((x + 7) ** 9) - 9)',
'(((x ^ 3) - 9) - 5)',
'(((2 + x) + x) * x)',
'(((x + 3) / 6) / 8)',
'(((x - 5) + 6) ** 2)',
'(1024 ^ (x / 5))',
'((3 - (x + 6)) + 3)',
'(((x ^ 3) + 9) * 6)',
);
while (TRUE)
{
$changed = FALSE;
// Rule 1: (x - x) = 0
for ($i = 0; $i < count($Math_Formulas); $i++)
{
$Formula = trim(preg_replace_callback('/([^-]?)([a-z]+?) [-] ([a-z]+?)/', function($matches) {
$Expression = $matches[0];
if ($matches[2] == $matches[3])
{
$Expression = $matches[1] . '0';
}
return($Expression);
}, $Math_Formulas[$i]));
if ($Formula != $Math_Formulas[$i])
{
$changed = TRUE;
$Math_Formulas[$i] = $Formula;
}
}
// Rule 2: ...
if (!$changed)
{
break;
}
}
$Math_Formulas = array_values(array_unique($Math_Formulas));
?>
更新1:
我认为,如果在公式的创建中使用了“反向波兰符号”,一切都会简单得多,但对于我拥有的公式,我需要重新排列参数(按字母升序或降序排列),以便能够进行比较
在RPN中:
(x+4)+5)变为“x 4+5”
(X+5)+4)变为“X 5 4+”
如何比较两者?那么更大的功能呢
我认为我犯了一个错误,没有详细说明14个“正则表达式”中使用的技术,我正在应用这些技术尽可能地简化这些公式。此过程中有多个正则表达式:
原始公式:((4-5)+x)+8)
步骤1:两到两个常数的加法(或减法或乘法)和表达式的减法,不带括号
公式:(-1+x)+8)
步骤2:删除((n+-n)+-n)或(n+-(n+-n))的括号
公式:(-1+x+8)
步骤3:按字母降序对参数重新排序
公式:(x+8-1)
步骤4:在循环中,再次执行步骤1
最终公式:(x+7)
还有更多的变换,例如(x+x+x)变成(3*x),(-x+x)变成0
所有这些都变得非常漂亮,但当我遇到((x*9)*(x*5))/9之类的函数时,这种逻辑失去了效率。我必须创建至少一个或14个其他嵌套规则。因此,一般方案是首先将表达式转换为表达式树格式。这是一种树形结构,其中每个节点表示一个数学运算、一个数字或一个变量。您可以使用调车场算法进行转换,并且可能会发现可以修改evalmath以生成树,而不是简单地对其进行评估。可能还有其他Python库可以做得比evalmath更多 一旦你有了一个树结构,它就变得更容易操作了。你可以运用高中时学过的一些数学规则,操纵小的子树来生成更简单的形式 例如,您可能希望展开方括号。表达式(x+3)*(x+5)将表示为一棵树,如下所示:
*
+ +
x 3 x 5
此树可以重写为x^2+8 x+15
+
^ +
x 2 * 15
x 8
总的计划可能会扩大你所有的范围。然后收集相似的术语并简化 只允许四个运算(
+-*/
),所有这些表达式都是所谓的有理分数,即两个多项式的比率
事实上,以下规则适用:
p/q + p'/q' = (pq' + p'q)/pq
p/p.p'/'q = (pp')/(qq')
(p/p')/(q/q') = (pq')/(p'q)
所以两个有理分式的组合也是一个有理分式
您可以实现一个系统,其中每个表达式都被描述为一对多项式(具有整数或有理系数),并集成上述公式。这本质上需要多项式加法和乘法
有时,分子和分母将有共同的因素,加以简化。您可以通过多项式上的欧几里德算法发现这些,给出多项式GCD。(然后还需要多项式除法。)
通过这个系统,简化将自行实现。此外,表达式将被规范化,以便您可以发现重复项
如果只有一个变量,多项式将是单变量的,并且它们的表示很简单。对于多个变量,它将成为一个li
(1 - x / y) (x + y) + (x * x) / y
1 - x / y => (y - x) / y
x + y => (x + y) / 1
(y - x) / y . (x + y) / 1 => (y² - x²) / y
x * x => x² / 1
y => y / 1
(x * x) / y => x² / y
(y² - x²) / y + x² / y => y³ / y²
y³ / y² => y / 1