Résumé de la modification
- Ma réponse originale à cette question simplement noté que le code contenait beaucoup de réplication des calculs et que la plupart des puissances impliquées facteurs de 1/3. Par exemple,
pow(x, 0.1e1/0.3e1)
est le même que cbrt(x)
.
- Mon deuxième édition a été tout simplement faux, et et mon troisième extrapoler sur ce qu'est le mal. C'est ce qui fait peur aux gens de changer l'oracle comme les résultats de symbolique programmes de mathématiques qui commencent par la lettre 'M'. J'ai radié (c'est à dire,
grève) ces modifications et les ont poussés vers le bas de la révision actuelle de cette réponse. Cependant, je n'ai pas les supprimer. Je suis humain. Il est facile pour nous de faire une erreur.
- Mon quatrième édition développé une très compact expression qui représente correctement le tube d'expression dans la question SI les paramètres
l1
, l2
, et l3
sont des nombres réels positifs et si a
est un non-zéro nombre réel. (Nous n'avons pas encore entendre parler de l'OP au sujet de la nature spécifique de ces coefficients. Compte tenu de la nature du problème, ce sont des hypothèses raisonnables.)
- Cette modification vise à répondre à la générique problème de la façon de simplifier ces expressions.
Tout d'abord
J'ai utiliser Maple pour générer le code C++ pour éviter les erreurs.
Maple et Mathematica manquent parfois de l'évidence. Plus important encore, les utilisateurs de Maple et Mathematica parfois faire des erreurs. En substituant "souvent", ou peut-être même "presque toujours", en lieu et place de "parfois, est probablement plus proche de la marque.
Vous pourriez avoir aidé Érable simplifier cette expression en disant cela sur les paramètres en question. Dans l'exemple à portée de main, je soupçonne qu' l1
, l2
, et l3
sont des nombres réels positifs et qu' a
est un non-zéro nombre réel. Si c'est le cas, dites-lui que. Ceux symbolique programmes de mathématiques supposent généralement les quantités à traiter sont complexes. En restreignant le domaine permet au programme de faire des hypothèses qui ne sont pas valides dans les nombres complexes.
Comment simplifier ces grandes messes de symbolique programmes de mathématiques (cette édition)
Symbolique programmes de mathématiques fournissent généralement la capacité à fournir des informations sur les différents paramètres. L'utilisation de cette capacité, en particulier si votre problème implique la division ou de l'exponentiation. Dans l'exemple à portée de main, vous pourriez avoir aidé Érable simplifier cette expression en disant que l1
, l2
, et l3
sont des nombres réels positifs et qu' a
est un non-zéro nombre réel. Si c'est le cas, dites-lui que. Ceux symbolique programmes de mathématiques supposent généralement les quantités à traiter sont complexes. En restreignant le domaine permet au programme de faire des hypothèses telles que axbx=(ab)x. Ce n'est que si a
et b
sont des nombres réels positifs et si x
est réel. Il n'est pas valide dans les nombres complexes.
En fin de compte, ceux symbolique programmes de mathématiques de suivre les algorithmes. Aider le long. Essayez de jouer avec de l'expansion, de la collecte, et de simplifier avant de générer le code. Dans ce cas, vous pourriez avoir rassemblé ces conditions impliquant un facteur de mu
et ceux impliquant un facteur d' K
. Réduire une expression à sa "forme la plus simple" reste un peu d'un art.
Lorsque vous obtenez une horrible gâchis de code généré, ne pas l'accepter comme une vérité que vous ne devez pas toucher. Essayez de simplifier vous-même. Regardez ce que la symbolique programme de mathématiques était saisie du code généré. Regardez comment j'ai réduit votre expression de quelque chose de beaucoup plus simple et beaucoup plus rapide, et la façon de Walter réponse a pris la mienne en plusieurs étapes supplémentaires. Il n'y a pas de recette magique. Si il y avait une recette magique, Érable serait appliqué et que, compte tenu de la réponse que Walter a donné.
Sur la question spécifique
Vous faites beaucoup de l'addition et de la soustraction dans ce calcul. Vous pouvez obtenir dans le pétrin si vous avez des conditions que près de s'annuler l'un l'autre. Vous perdez beaucoup de CPU si vous avez un terme qui domine sur les autres.
Ensuite, vous perdez beaucoup de CPU en effectuant les calculs qui se répètent. Sauf si vous avez activé l' -ffast-math
, ce qui permet au compilateur de briser les règles de la virgule flottante IEEE, le compilateur ne va pas (en fait, ne doit pas) simplifier cette expression pour vous. Il va plutôt faire exactement ce que vous lui avez dit de faire. Au minimum, vous devez calculer l1 * l2 * l3
avant le calcul de ce désordre.
Enfin, vous faites beaucoup d'appels à l' pow
, ce qui est extrêmement lent. Notez que plusieurs de ces appels sont de la forme (l1*l2*l3)(1/3). Beaucoup de ces appels à l' pow
a pu être effectuées avec un seul appel à l' std::cbrt
:
l123 = l1 * l2 * l3;
l123_pow_1_3 = std::cbrt(l123);
l123_pow_4_3 = l123 * l123_pow_1_3;
Avec cela,
-
X * pow(l1 * l2 * l3, 0.1e1 / 0.3e1)
devient X * l123_pow_1_3
.
-
X * pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
devient X / l123_pow_1_3
.
-
X * pow(l1 * l2 * l3, 0.4e1 / 0.3e1)
devient X * l123_pow_4_3
.
-
X * pow(l1 * l2 * l3, -0.4e1 / 0.3e1)
devient X / l123_pow_4_3
.
Maple ne manquez évidence.
Par exemple, il y a un moyen beaucoup plus facile à écrire
(pow(l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * pow(l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
En supposant que l' l1
, l2
, et l3
sont réels plutôt que des nombres complexes, et que la véritable racine cubique (plutôt que sur le principe racines complexes) sont susceptibles d'être extraites, le ci-dessus se réduit à
2.0/(3.0 * pow(l1 * l2 * l3, 1.0/3.0))
ou
2.0/(3.0 * l123_pow_1_3)
À l'aide de cbrt_l123
au lieu de l123_pow_1_3
, le méchant de l'expression dans la question se réduit à
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);
Toujours vérifier deux fois, mais toujours de simplifier ainsi.
Voici quelques unes de mes étapes pour en arriver à la ci-dessus:
// 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);
Mauvaise réponse, intentionnellement pour l'humilité
Notez que c'est frappée. C'est faux.
Mise à jour
Maple ne manquez évidence. Par exemple, il y a un moyen beaucoup plus facile à écrire
(pow(l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * pow(l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
En supposant que l' l1
, l2
, et l3
sont réels plutôt que des nombres complexes, et que la véritable racine cubique (plutôt que sur le principe racines complexes) sont susceptibles d'être extraites, le ci-dessus se réduit à zéro. Ce calcul de zéro est répété de nombreuses fois.
Deuxième mise à jour
Si j'ai bien fait le droit de mathématiques (il n'y a pas de garantie que j'ai déjà fait le droit de mathématiques), le méchant de l'expression dans la question se réduit à
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);
Ce qui précède suppose qu' l1
, l2
, et l3
sont des nombres réels positifs.