编辑摘要
- 我最初的回答只是指出该代码包含许多重复的计算,并且许多幂涉及1/3的因数。例如,
pow(x, 0.1e1/0.3e1)
与相同cbrt(x)
。
- 我的第二次编辑是错误的,而我的第三次编辑是根据这种错误推断的。这就是使人们害怕更改以字母“ M”开头的符号数学程序的类似于oracle的结果的原因。我已经剔除(即
删除)这些编辑并将它们推到该答案的当前修订版本的底部。但是,我没有删除它们。我是人类。我们很容易犯错。
- 我的第四个编辑开发了一个非常紧凑的表达式正确代表的问题令人费解的表情IF参数
l1
,l2
和l3
是正实数,如果a
是非零实数。(我们尚未从OP那里听到有关这些系数的具体性质的信息。鉴于问题的性质,这些都是合理的假设。)
- 此编辑试图回答如何简化这些表达式的一般性问题。
第一件事
我使用Maple生成C ++代码以避免错误。
枫树和Mathematica有时会错过明显的地方。更重要的是,Maple和Mathematica的用户有时会犯错误。代替“有时”或什至“几乎总是”代替“有时可能更接近商标”。
您可以通过告诉Maple有关的参数来帮助Maple简化该表达式。在手边的例子,我怀疑l1
,l2
和l3
是正实数,并且a
是非零实数。如果是这样,请告知。这些符号数学程序通常假定手头的数量很复杂。限制域可以使程序做出在复数中无效的假设。
如何简化符号数学程序带来的麻烦(此编辑)
符号数学程序通常提供提供有关各种参数的信息的能力。使用该功能,尤其是当您的问题涉及除法或求幂时。在手边的例子,你可以帮助枫告诉它该简化的表达l1
,l2
和l3
是正实数,并且a
是非零实数。如果是这样,请告知。这些符号数学程序通常假定手头的数量很复杂。限制域使程序可以做出诸如a x b x =(ab)x的假设。仅当a
和b
为正实数且x
为实数时。在复数中无效。
最终,这些符号数学程序遵循算法。帮助它。在生成代码之前,请尝试进行扩展,收集和简化。在这种情况下,您可能已经收集了涉及因素为mu
和的因素K
。将表达式简化为“最简单的形式”仍然有些技巧。
当您看到一堆丑陋的生成代码时,请不要将其视为不可触摸的事实。尝试自己简化它。看一下符号数学程序在生成代码之前所拥有的内容。看看我是如何将您的表情简化为更简单,更快的,以及Walter的回答如何使我的表达更进一步。没有神奇的配方。如果有一个神奇的配方,那么枫树就会应用它,并给出沃尔特给出的答案。
关于具体问题
您在该计算中进行了很多加减运算。如果您的条款几乎互相抵消,您将陷入困境。如果您有一个术语要主导其他术语,那么您将浪费大量CPU。
接下来,通过执行重复计算会浪费大量CPU。除非您启用-ffast-math
,否则编译器将破坏IEEE浮点的某些规则,否则编译器将不会(实际上一定不能)为您简化该表达式。相反,它将完全按照您的指示执行操作。至少,您应该l1 * l2 * l3
在计算混乱之前进行计算。
最后,您对进行了很多调用pow
,这非常慢。请注意,其中一些调用的形式为(l1 * l2 * l3)(1/3)。这些调用中的许多调用pow
都可以通过一个调用来执行std::cbrt
:
l123 = l1 * l2 * l3;
l123_pow_1_3 = std::cbrt(l123);
l123_pow_4_3 = l123 * l123_pow_1_3;
有了这个,
X * pow(l1 * l2 * l3, 0.1e1 / 0.3e1)
成为X * l123_pow_1_3
。
X * pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
成为X / l123_pow_1_3
。
X * pow(l1 * l2 * l3, 0.4e1 / 0.3e1)
成为X * l123_pow_4_3
。
X * pow(l1 * l2 * l3, -0.4e1 / 0.3e1)
成为X / l123_pow_4_3
。
枫树确实错过了明显的事情。
例如,有一种更简单的书写方式
(pow(l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * pow(l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
假设l1
,l2
和l3
是实而非复数,而真正立方根(而不是原则复杂根)将被提取的,上述减少到
2.0/(3.0 * pow(l1 * l2 * l3, 1.0/3.0))
要么
2.0/(3.0 * l123_pow_1_3)
使用cbrt_l123
代替l123_pow_1_3
,问题中的讨厌表达简化为
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu/(3.0*l123)*( pow(l1/cbrt_l123,a)*(2.0*N1-N2-N3)
+ pow(l2/cbrt_l123,a)*(2.0*N2-N3-N1)
+ pow(l3/cbrt_l123,a)*(2.0*N3-N1-N2))
+K*(l123-1.0)*(N1+N2+N3);
始终要仔细检查,但也总是要简化。
这是我达到上述目标的一些步骤:
// Step 0: Trim all whitespace.
T=(mu*(pow(l1*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a*(pow(l1*l2*l3,-0.1e1/0.3e1)-l1*l2*l3*pow(l1*l2*l3,-0.4e1/0.3e1)/0.3e1)*pow(l1*l2*l3,0.1e1/0.3e1)/l1-pow(l2*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l1/0.3e1-pow(l3*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l1/0.3e1)/a+K*(l1*l2*l3-0.1e1)*l2*l3)*N1/l2/l3+(mu*(-pow(l1*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l2/0.3e1+pow(l2*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a*(pow(l1*l2*l3,-0.1e1/0.3e1)-l1*l2*l3*pow(l1*l2*l3,-0.4e1/0.3e1)/0.3e1)*pow(l1*l2*l3,0.1e1/0.3e1)/l2-pow(l3*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l2/0.3e1)/a+K*(l1*l2*l3-0.1e1)*l1*l3)*N2/l1/l3+(mu*(-pow(l1*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l3/0.3e1-pow(l2*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l3/0.3e1+pow(l3*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a*(pow(l1*l2*l3,-0.1e1/0.3e1)-l1*l2*l3*pow(l1*l2*l3,-0.4e1/0.3e1)/0.3e1)*pow(l1*l2*l3,0.1e1/0.3e1)/l3)/a+K*(l1*l2*l3-0.1e1)*l1*l2)*N3/l1/l2;
// Step 1:
// l1*l2*l3 -> l123
// 0.1e1 -> 1.0
// 0.4e1 -> 4.0
// 0.3e1 -> 3
l123 = l1 * l2 * l3;
T=(mu*(pow(l1*pow(l123,-1.0/3),a)*a*(pow(l123,-1.0/3)-l123*pow(l123,-4.0/3)/3)*pow(l123,1.0/3)/l1-pow(l2*pow(l123,-1.0/3),a)*a/l1/3-pow(l3*pow(l123,-1.0/3),a)*a/l1/3)/a+K*(l123-1.0)*l2*l3)*N1/l2/l3+(mu*(-pow(l1*pow(l123,-1.0/3),a)*a/l2/3+pow(l2*pow(l123,-1.0/3),a)*a*(pow(l123,-1.0/3)-l123*pow(l123,-4.0/3)/3)*pow(l123,1.0/3)/l2-pow(l3*pow(l123,-1.0/3),a)*a/l2/3)/a+K*(l123-1.0)*l1*l3)*N2/l1/l3+(mu*(-pow(l1*pow(l123,-1.0/3),a)*a/l3/3-pow(l2*pow(l123,-1.0/3),a)*a/l3/3+pow(l3*pow(l123,-1.0/3),a)*a*(pow(l123,-1.0/3)-l123*pow(l123,-4.0/3)/3)*pow(l123,1.0/3)/l3)/a+K*(l123-1.0)*l1*l2)*N3/l1/l2;
// Step 2:
// pow(l123,1.0/3) -> cbrt_l123
// l123*pow(l123,-4.0/3) -> pow(l123,-1.0/3)
// (pow(l123,-1.0/3)-pow(l123,-1.0/3)/3) -> 2.0/(3.0*cbrt_l123)
// *pow(l123,-1.0/3) -> /cbrt_l123
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T=(mu*(pow(l1/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l1-pow(l2/cbrt_l123,a)*a/l1/3-pow(l3/cbrt_l123,a)*a/l1/3)/a+K*(l123-1.0)*l2*l3)*N1/l2/l3+(mu*(-pow(l1/cbrt_l123,a)*a/l2/3+pow(l2/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l2-pow(l3/cbrt_l123,a)*a/l2/3)/a+K*(l123-1.0)*l1*l3)*N2/l1/l3+(mu*(-pow(l1/cbrt_l123,a)*a/l3/3-pow(l2/cbrt_l123,a)*a/l3/3+pow(l3/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l3)/a+K*(l123-1.0)*l1*l2)*N3/l1/l2;
// Step 3:
// Whitespace is nice.
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
(mu*( pow(l1/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l1
-pow(l2/cbrt_l123,a)*a/l1/3
-pow(l3/cbrt_l123,a)*a/l1/3)/a
+K*(l123-1.0)*l2*l3)*N1/l2/l3
+(mu*(-pow(l1/cbrt_l123,a)*a/l2/3
+pow(l2/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l2
-pow(l3/cbrt_l123,a)*a/l2/3)/a
+K*(l123-1.0)*l1*l3)*N2/l1/l3
+(mu*(-pow(l1/cbrt_l123,a)*a/l3/3
-pow(l2/cbrt_l123,a)*a/l3/3
+pow(l3/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l3)/a
+K*(l123-1.0)*l1*l2)*N3/l1/l2;
// Step 4:
// Eliminate the 'a' in (term1*a + term2*a + term3*a)/a
// Expand (mu_term + K_term)*something to mu_term*something + K_term*something
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
(mu*( pow(l1/cbrt_l123,a)*2.0/(3.0*cbrt_l123)*cbrt_l123/l1
-pow(l2/cbrt_l123,a)/l1/3
-pow(l3/cbrt_l123,a)/l1/3))*N1/l2/l3
+K*(l123-1.0)*l2*l3*N1/l2/l3
+(mu*(-pow(l1/cbrt_l123,a)/l2/3
+pow(l2/cbrt_l123,a)*2.0/(3.0*cbrt_l123)*cbrt_l123/l2
-pow(l3/cbrt_l123,a)/l2/3))*N2/l1/l3
+K*(l123-1.0)*l1*l3*N2/l1/l3
+(mu*(-pow(l1/cbrt_l123,a)/l3/3
-pow(l2/cbrt_l123,a)/l3/3
+pow(l3/cbrt_l123,a)*2.0/(3.0*cbrt_l123)*cbrt_l123/l3))*N3/l1/l2
+K*(l123-1.0)*l1*l2*N3/l1/l2;
// Step 5:
// Rearrange
// Reduce l2*l3*N1/l2/l3 to N1 (and similar)
// Reduce 2.0/(3.0*cbrt_l123)*cbrt_l123/l1 to 2.0/3.0/l1 (and similar)
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
(mu*( pow(l1/cbrt_l123,a)*2.0/3.0/l1
-pow(l2/cbrt_l123,a)/l1/3
-pow(l3/cbrt_l123,a)/l1/3))*N1/l2/l3
+(mu*(-pow(l1/cbrt_l123,a)/l2/3
+pow(l2/cbrt_l123,a)*2.0/3.0/l2
-pow(l3/cbrt_l123,a)/l2/3))*N2/l1/l3
+(mu*(-pow(l1/cbrt_l123,a)/l3/3
-pow(l2/cbrt_l123,a)/l3/3
+pow(l3/cbrt_l123,a)*2.0/3.0/l3))*N3/l1/l2
+K*(l123-1.0)*N1
+K*(l123-1.0)*N2
+K*(l123-1.0)*N3;
// Step 6:
// Factor out mu and K*(l123-1.0)
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu*( ( pow(l1/cbrt_l123,a)*2.0/3.0/l1
-pow(l2/cbrt_l123,a)/l1/3
-pow(l3/cbrt_l123,a)/l1/3)*N1/l2/l3
+ (-pow(l1/cbrt_l123,a)/l2/3
+pow(l2/cbrt_l123,a)*2.0/3.0/l2
-pow(l3/cbrt_l123,a)/l2/3)*N2/l1/l3
+ (-pow(l1/cbrt_l123,a)/l3/3
-pow(l2/cbrt_l123,a)/l3/3
+pow(l3/cbrt_l123,a)*2.0/3.0/l3)*N3/l1/l2)
+K*(l123-1.0)*(N1+N2+N3);
// Step 7:
// Expand
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu*( pow(l1/cbrt_l123,a)*2.0/3.0/l1*N1/l2/l3
-pow(l2/cbrt_l123,a)/l1/3*N1/l2/l3
-pow(l3/cbrt_l123,a)/l1/3*N1/l2/l3
-pow(l1/cbrt_l123,a)/l2/3*N2/l1/l3
+pow(l2/cbrt_l123,a)*2.0/3.0/l2*N2/l1/l3
-pow(l3/cbrt_l123,a)/l2/3*N2/l1/l3
-pow(l1/cbrt_l123,a)/l3/3*N3/l1/l2
-pow(l2/cbrt_l123,a)/l3/3*N3/l1/l2
+pow(l3/cbrt_l123,a)*2.0/3.0/l3*N3/l1/l2)
+K*(l123-1.0)*(N1+N2+N3);
// Step 8:
// Simplify.
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu/(3.0*l123)*( pow(l1/cbrt_l123,a)*(2.0*N1-N2-N3)
+ pow(l2/cbrt_l123,a)*(2.0*N2-N3-N1)
+ pow(l3/cbrt_l123,a)*(2.0*N3-N1-N2))
+K*(l123-1.0)*(N1+N2+N3);
错误的答案,故意保持谦卑
请注意,这很糟糕。这是不对的。
更新资料
枫树确实错过了明显的事情。例如,有一种更简单的书写方式
(pow(l1 * l2 * l3,-0.1e1 / 0.3e1)-l1 * l2 * l3 * pow(l1 * l2 * l3,-0.4e1 / 0.3e1)/ 0.3e1)
假设l1
,l2
和l3
是实而非复数,而真正立方根(而不是原则复杂根)是要被提取,上述减小到零。零的计算重复了很多次。
第二次更新
如果我已经正确地进行了数学运算(不能保证我已经正确地进行了数学运算),则问题中令人讨厌的表达式将简化为
l123 = l1 * l2 * l3;
cbrt_l123_inv = 1.0 / cbrt(l123);
nasty_expression =
K * (l123 - 1.0) * (N1 + N2 + N3)
- ( pow(l1 * cbrt_l123_inv, a) * (N2 + N3)
+ pow(l2 * cbrt_l123_inv, a) * (N1 + N3)
+ pow(l3 * cbrt_l123_inv, a) * (N1 + N2)) * mu / (3.0*l123);
以上假设l1
,l2
和l3
是正实数。
pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
用一个变量替换所有变量。您需要对代码进行基准测试,以确保它运行的快慢。