概要を編集
- 私の最初の答えは、コードに多くの複製された計算が含まれていて、その能力の多くが1/3の要素を含んでいることを指摘しただけです。たとえば
pow(x, 0.1e1/0.3e1)
、はと同じcbrt(x)
です。
- 私の2番目の編集は間違っていたので、3番目の編集はこの間違いを推定したものです。これが、人々が文字「M」で始まる象徴的な数学プログラムからの神託のような結果を変更することを恐れさせるものです。私はそれらの編集を打ち消し(つまり、
ストライク)、この回答の現在のリビジョンの一番下にプッシュしました。ただし、削除しませんでした。私は人間です。私たちは間違いを犯しやすい。
- 私の第四編集は正しく、問題の複雑な式を表していることを非常にコンパクトな表現開発のIFパラメータ
l1
、l2
およびl3
場合は正の実数であり、a
非ゼロの実数であるが。(これらの係数の具体的な性質については、OPからまだ連絡がありません。問題の性質を考えると、これらは合理的な仮定です。)
- この編集は、これらの式を単純化する方法の一般的な問題に答えようとします。
まず最初に
Mapleを使用してC ++コードを生成し、間違いを回避しています。
MapleとMathematicaは時々明白を逃します。さらに重要なことに、MapleとMathematicaのユーザーは時々間違いを犯します。「時々」、または「ほとんど常に」の代わりに「時々」を置き換えることは、「時々、マークに近い」でしょう。
問題のパラメータについて伝えることで、Mapleが式を簡略化するのを助けることができます。手近な例では、私はそれを疑うl1
、l2
と、l3
正の実数であり、それがa
ゼロ以外の実数です。その場合は、それを伝えてください。これらのシンボリック数学プログラムは、通常、手元にある数量が複雑であると想定しています。ドメインを制限すると、プログラムは複素数では無効な仮定を行うことができます。
シンボリック数学プログラムからこれらの大きな混乱を単純化する方法(この編集)
シンボリック数学プログラムは通常、さまざまなパラメーターに関する情報を提供する機能を提供します。特に、問題に除算や指数が含まれる場合は、その能力を使用してください。手近な例では、ということを伝えることで、その式の簡素化メープルを助けたかもしれないl1
、l2
と、l3
正の実数であり、それがa
ゼロ以外の実数です。その場合は、それを伝えてください。これらのシンボリック数学プログラムは、通常、手元にある数量が複雑であると想定しています。ドメインを制限すると、プログラムはa x b x =(ab)xなどの仮定を行うことができます。これはa
、b
正の実数であり、かつ実数である場合に限られx
ます。複素数では無効です。
最終的に、これらのシンボリック数学プログラムはアルゴリズムに従います。それを手伝ってください。コードを生成する前に、拡張、収集、および簡略化を試してみてください。このケースでは、それらの要因が関与する観点から収集している可能性mu
の要因が関与するものをK
。表現を「最も単純な形式」に縮小することは、まだ芸術の一部です。
生成されたコードの醜い混乱を受け取ったら、それをあなたが触れてはならない真実として受け入れないでください。自分で簡単にしてみてください。シンボリック数学プログラムがコードを生成する前に持っていたものを見てください。私があなたの表現をもっと単純ではるかに速いものにどのように減らしたか、そしてウォルターの答えが私にさらにいくつかのステップを取った方法を見てください。魔法のレシピはありません。魔法のレシピがあれば、メープルはそれを適用し、ウォルターが答えたでしょう。
特定の質問について
あなたはその計算で多くの加算と減算を行っています。互いにほとんど打ち消し合う条件がある場合、深刻な問題に陥ることがあります。1つの用語が他の用語よりも優位である場合、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
2回目の更新
私が数学の正しいことをした場合(私が数学の正しいことをしたという保証はありません)、質問の厄介な表現は次のようになります。
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)
を変数に置き換えることです...ただし、コードが高速か低速かを確認するには、コードをベンチマークする必要があります。