我会努力在这个问题上保持客观。
我有一个数据库,其中包含由应用程序创建的数百万个数学公式,这些是遵循逻辑的公式:
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中创建了一个例程来进行替换,我设法在一个特定的公式中从8千种可能性减少到不到300种,从而取得了巨大的进步。
然而,由于公式的大小(并非复杂因为它们并不复杂)增加了,我的例程再也不能有效了。
我需要一种算法,而不是常规,来应用我们在学校学到的数学减少。
我认为这是可能的,因为公式是标准化的,并且限于5个基本的数学运算。
我正在使用GitHub中获得的EvalMath类来帮助减少和执行公式。
为了给你一个更好的主意,公式是抽象的,每个“@”由常量和变量实时替换。
(@ + @)
(@ / @)
(@ ** @)
((@ + @) + @)
((@ + @) ** @)
((@ - @) + @)
((@ - @) / @)
((@ - @) ** @)
((@ * @) + @)
((@ * @) / @)
((@ * @) ** @)
((@ / @) / @)
这是一段PHP代码,是我的简化程序的一部分。
在WHILE(TRUE)中,我将规则重复,直到没有替换为止。
最后,我有一个数组,其中包含许多重复数据,通过对公式元素进行一些缩减和重新排序,这是array_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个其他嵌套规则。
答案 0 :(得分:1)
因此,一般方案是首先将表达式转换为表达式树格式。这是树结构,其中每个节点表示数学运算,数字或变量。您可以使用分流码算法进行转换,并且可能会发现可以修改evalmath以生成树而不是简单地对其进行评估。可能还有其他Python库可以做的不仅仅是evalmath。
一旦你有了一个树形结构,它就会变得更容易操作。你可以操纵小的子树来制作更简单的形式,应用你在高中学到的一些数学规则。
例如,您可能希望展开括号。表达式(x + 3)*(x + 5)将表示为树
*
+ +
x 3 x 5
这棵树可以重写为x ^ 2 + 8 x + 15
+
^ +
x 2 * 15
x 8
一般方案可能会扩展所有括号。然后收集类似的术语并简化。