Zusammenfassung bearbeiten
- In meiner ursprünglichen Antwort wurde lediglich festgestellt, dass der Code viele replizierte Berechnungen enthielt und dass viele der Potenzen Faktoren von 1/3 beinhalteten. Zum Beispiel
pow(x, 0.1e1/0.3e1)
ist das gleiche wie cbrt(x)
.
- Meine zweite Bearbeitung war einfach falsch, und meine dritte wurde auf diese Unrichtigkeit hochgerechnet. Dies ist es, was Menschen Angst macht, die orakelartigen Ergebnisse von symbolischen Mathematikprogrammen zu ändern, die mit dem Buchstaben 'M' beginnen. Ich habe diese Änderungen gestrichen (dh
gestrichen ) und sie an den Grund der aktuellen Überarbeitung dieser Antwort verschoben. Ich habe sie jedoch nicht gelöscht. Ich bin menschlich. Es fällt uns leicht, einen Fehler zu machen.
- Mein vierte bearbeiten entwickelte einen sehr kompakten Ausdruck, korrekt gefalteten Ausdruck in der Frage stellt IF die Parameter
l1
, l2
und l3
positive reelle Zahlen sind und wenn a
eine Nicht-Null reelle Zahl. (Wir haben vom OP noch nichts über die Spezifität dieser Koeffizienten gehört. Angesichts der Art des Problems sind dies vernünftige Annahmen.)
- Diese Bearbeitung versucht, das allgemeine Problem der Vereinfachung dieser Ausdrücke zu beantworten.
Das wichtigste zuerst
Ich verwende Maple, um den C ++ - Code zu generieren, um Fehler zu vermeiden.
Maple und Mathematica vermissen manchmal das Offensichtliche. Noch wichtiger ist, dass die Benutzer von Maple und Mathematica manchmal Fehler machen. Das Ersetzen von "oft" oder vielleicht sogar "fast immer" anstelle von "manchmal" ist wahrscheinlich näher an der Marke.
Sie hätten Maple helfen können, diesen Ausdruck zu vereinfachen, indem Sie ihm die fraglichen Parameter mitteilen. Im Beispiel auf der Hand, vermute ich , dass l1
, l2
und l3
positive reelle Zahlen sind und das a
ist eine von Null verschiedene reelle Zahl. Wenn das der Fall ist, sagen Sie es das. Diese symbolischen Mathematikprogramme gehen normalerweise davon aus, dass die vorliegenden Größen komplex sind. Durch die Einschränkung der Domäne kann das Programm Annahmen treffen, die in den komplexen Zahlen nicht gültig sind.
Wie man diese großen Probleme mit symbolischen Mathematikprogrammen vereinfacht (diese Bearbeitung)
Symbolische Mathematikprogramme bieten normalerweise die Möglichkeit, Informationen über die verschiedenen Parameter bereitzustellen. Verwenden Sie diese Fähigkeit, insbesondere wenn Ihr Problem Teilung oder Potenzierung beinhaltet. Im Beispiel auf der Hand, hätte Ihnen geholfen Maple diesen Ausdruck zu vereinfachen , indem sie das sagen l1
, l2
und l3
positive reelle Zahlen sind und das a
ist eine von Null verschiedene reelle Zahl. Wenn das der Fall ist, sagen Sie es das. Diese symbolischen Mathematikprogramme gehen normalerweise davon aus, dass die vorliegenden Größen komplex sind. Durch Einschränken der Domäne kann das Programm Annahmen wie a x b x = (ab) x treffen . Dies ist nur dann, wenn a
und b
positive reelle Zahlen sind und wenn x
es real ist. Es ist in den komplexen Zahlen nicht gültig.
Letztendlich folgen diese symbolischen Mathematikprogramme Algorithmen. Helfen Sie mit. Versuchen Sie, mit dem Erweitern, Sammeln und Vereinfachen zu spielen, bevor Sie Code generieren. In diesem Fall hätten Sie die Begriffe mit einem Faktor von mu
und die mit einem Faktor von sammeln können K
. Das Reduzieren eines Ausdrucks auf seine "einfachste Form" bleibt eine Kunst.
Wenn Sie ein hässliches Durcheinander von generiertem Code erhalten, akzeptieren Sie ihn nicht als eine Wahrheit, die Sie nicht berühren dürfen. Versuchen Sie es selbst zu vereinfachen. Schauen Sie sich an, was das symbolische Mathematikprogramm hatte, bevor es Code generierte. Schau dir an, wie ich deinen Ausdruck auf etwas viel Einfacheres und viel Schnelleres reduziert habe und wie Walters Antwort meine einige Schritte weiter gebracht hat. Es gibt kein Zauberrezept. Wenn es ein magisches Rezept gegeben hätte, hätte Maple es angewendet und die Antwort gegeben, die Walter gegeben hat.
Über die spezifische Frage
Sie addieren und subtrahieren viel in dieser Berechnung. Sie können in große Schwierigkeiten geraten, wenn Sie Begriffe haben, die sich fast gegenseitig aufheben. Sie verschwenden viel CPU, wenn Sie einen Begriff haben, der die anderen dominiert.
Als nächstes verschwenden Sie viel CPU, indem Sie wiederholte Berechnungen durchführen. Sofern Sie nicht aktiviert haben -ffast-math
, wodurch der Compiler einige der Regeln des IEEE-Gleitkommas brechen kann, wird der Compiler diesen Ausdruck für Sie nicht (in der Tat nicht) vereinfachen. Es wird stattdessen genau das tun, was Sie ihm gesagt haben. Sie sollten mindestens rechnen, l1 * l2 * l3
bevor Sie dieses Durcheinander berechnen .
Schließlich telefonieren Sie viel pow
, was extrem langsam ist. Beachten Sie, dass einige dieser Aufrufe die Form (l1 * l2 * l3) (1/3) haben . Viele dieser Anrufe an pow
könnten mit einem einzigen Anruf an ausgeführt werden std::cbrt
:
l123 = l1 * l2 * l3;
l123_pow_1_3 = std::cbrt(l123);
l123_pow_4_3 = l123 * l123_pow_1_3;
Mit diesem,
X * pow(l1 * l2 * l3, 0.1e1 / 0.3e1)
wird X * l123_pow_1_3
.
X * pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
wird X / l123_pow_1_3
.
X * pow(l1 * l2 * l3, 0.4e1 / 0.3e1)
wird X * l123_pow_4_3
.
X * pow(l1 * l2 * l3, -0.4e1 / 0.3e1)
wird X / l123_pow_4_3
.
Maple vermisste das Offensichtliche.
Zum Beispiel gibt es eine viel einfachere Möglichkeit zu schreiben
(pow(l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * pow(l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
Vorausgesetzt, das l1
,l2
und l3
sind real und nicht komplexe Zahlen, und dass der reale Kubikwurzel ( und nicht das Prinzip komplexe root) extrahiert werden sollen, verringert sich die oben
2.0/(3.0 * pow(l1 * l2 * l3, 1.0/3.0))
oder
2.0/(3.0 * l123_pow_1_3)
Verwenden cbrt_l123
stattl123_pow_1_3
reduziert sich der böse Ausdruck in der Frage auf
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);
Immer überprüfen, aber auch immer vereinfachen.
Hier sind einige meiner Schritte, um zu den oben genannten Ergebnissen zu gelangen:
// 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);
Falsche Antwort, absichtlich aus Demut gehalten
Beachten Sie, dass dies betroffen ist. Es ist falsch.
Aktualisieren
Maple vermisste das Offensichtliche. Zum Beispiel gibt es eine viel einfachere Möglichkeit zu schreiben
(pow (l1 * l2 * l3, -0,1e1 / 0,3e1) - l1 * l2 * 13 * pow (l1 * l2 * l3, -0,4e1 / 0,3e1) / 0,3e1)
Vorausgesetzt, das l1
,l2
undl3
sind real und nicht komplexe Zahlen, und dass der reale Kubikwurzel ( und nicht das Prinzip komplexe root) extrahiert werden sollen, verringert sich die oben auf Null. Diese Berechnung von Null wird um ein Vielfaches wiederholt.
Zweites Update
Wenn ich die Mathematik richtig gemacht habe (es gibt keine Garantie dafür, dass ich die Mathematik richtig gemacht habe), reduziert sich der böse Ausdruck in der Frage auf
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);
Die oben geht davon aus, dass l1
, l2
und l3
positive reelle Zahlen sind .
pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
durch eine Variable zu ersetzen ... Sie müssen Ihren Code vergleichen, um sicherzugehen, ob er schnell oder langsam läuft.