Edit ringkasan
- Jawaban asli saya hanya mencatat bahwa kode tersebut berisi banyak perhitungan yang direplikasi dan banyak kekuatan yang melibatkan faktor 1/3. Misalnya,
pow(x, 0.1e1/0.3e1)
sama seperti cbrt(x)
.
- Suntingan kedua saya hanya salah, dan yang ketiga mengekstrapolasi kesalahan ini. Inilah yang membuat orang takut untuk mengubah hasil seperti ramalan dari program matematika simbolik yang dimulai dengan huruf 'M'. Saya telah menghentikan (yaitu,
mencoret ) hasil edit tersebut dan mendorongnya ke bagian bawah revisi saat ini dari jawaban ini. Namun, saya tidak menghapusnya. Saya manusia. Mudah bagi kami untuk membuat kesalahan.
- Keempat saya sunting mengembangkan ekspresi yang sangat kompak yang benar mewakili ekspresi berbelit-belit dalam pertanyaan JIKA parameter
l1
, l2
, dan l3
adalah bilangan real positif dan jika a
adalah nomor non-nol nyata. (Kami belum mendengar dari OP mengenai sifat spesifik dari koefisien ini. Mengingat sifat masalahnya, ini adalah asumsi yang masuk akal.)
- Pengeditan ini mencoba menjawab masalah umum tentang cara menyederhanakan ekspresi ini.
Hal pertama yang pertama
Saya menggunakan Maple untuk menghasilkan kode C ++ untuk menghindari kesalahan.
Maple dan Mathematica terkadang melewatkan yang sudah jelas. Yang lebih penting lagi, pengguna Maple dan Mathematica terkadang melakukan kesalahan. Mengganti "sering kali", atau mungkin bahkan "hampir selalu", sebagai pengganti "terkadang mungkin lebih dekat ke sasaran.
Anda bisa membantu Maple menyederhanakan ekspresi itu dengan menceritakan tentang parameter yang dimaksud. Pada contoh di tangan, saya menduga bahwa l1
, l2
, dan l3
adalah bilangan real positif dan bahwa a
adalah angka non-nol nyata. Jika itu masalahnya, katakan itu. Program matematika simbolis tersebut biasanya mengasumsikan besaran yang ada di tangan itu kompleks. Membatasi domain memungkinkan program membuat asumsi yang tidak valid dalam bilangan kompleks.
Bagaimana menyederhanakan kekacauan besar itu dari program matematika simbolis (edit ini)
Program matematika simbolik biasanya menyediakan kemampuan untuk memberikan informasi tentang berbagai parameter. Gunakan kemampuan itu, terutama jika masalah Anda melibatkan pembagian atau eksponensial. Pada contoh di tangan, Anda bisa membantu Maple menyederhanakan ekspresi itu dengan mengatakan bahwa l1
, l2
, dan l3
adalah bilangan real positif dan bahwa a
adalah angka non-nol nyata. Jika itu masalahnya, katakan itu. Program matematika simbolis tersebut biasanya mengasumsikan jumlah yang ada di tangan itu kompleks. Membatasi domain memungkinkan program membuat asumsi seperti a x b x = (ab) x . Ini hanya jika a
dan b
adalah bilangan real positif dan jika x
nyata. Ini tidak valid dalam bilangan kompleks.
Pada akhirnya, program matematika simbolis tersebut mengikuti algoritma. Bantu itu. Cobalah bermain dengan memperluas, mengumpulkan, dan menyederhanakan sebelum Anda menghasilkan kode. Dalam kasus ini, Anda bisa mengumpulkan suku-suku yang melibatkan faktor dari mu
dan yang melibatkan faktor K
. Mereduksi ekspresi menjadi "bentuk paling sederhana" tetap merupakan seni.
Ketika Anda mendapatkan kode yang dihasilkan berantakan, jangan menerimanya sebagai kebenaran yang tidak boleh Anda sentuh. Coba sederhanakan sendiri. Lihatlah apa yang dimiliki program matematika simbolik sebelum ia menghasilkan kode. Lihatlah bagaimana saya mengurangi ekspresi Anda menjadi sesuatu yang jauh lebih sederhana dan lebih cepat, dan bagaimana jawaban Walter membawa saya beberapa langkah lebih jauh. Tidak ada resep ajaib. Jika ada resep ajaib, Maple akan menerapkannya dan memberikan jawaban yang diberikan Walter.
Tentang pertanyaan spesifik
Anda melakukan banyak penambahan dan pengurangan dalam perhitungan itu. Anda bisa mendapat masalah besar jika Anda memiliki persyaratan yang hampir membatalkan satu sama lain. Anda membuang banyak CPU jika Anda memiliki satu istilah yang mendominasi yang lain.
Selanjutnya, Anda membuang banyak CPU dengan melakukan penghitungan berulang. Kecuali Anda telah mengaktifkannya -ffast-math
, yang memungkinkan kompilator melanggar beberapa aturan titik mengambang IEEE, kompilator tidak akan (pada kenyataannya, tidak boleh) menyederhanakan ekspresi itu untuk Anda. Ia malah akan melakukan persis seperti yang Anda perintahkan. Minimal, Anda harus menghitung l1 * l2 * l3
sebelum menghitung kekacauan itu.
Terakhir, Anda melakukan banyak panggilan ke pow
, yang sangat lambat. Perhatikan bahwa beberapa dari panggilan tersebut dalam bentuk (l1 * l2 * l3) (1/3) . Banyak dari panggilan ke pow
tersebut dapat dilakukan dengan satu panggilan ke std::cbrt
:
l123 = l1 * l2 * l3;
l123_pow_1_3 = std::cbrt(l123);
l123_pow_4_3 = l123 * l123_pow_1_3;
Dengan ini,
X * pow(l1 * l2 * l3, 0.1e1 / 0.3e1)
menjadi X * l123_pow_1_3
.
X * pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
menjadi X / l123_pow_1_3
.
X * pow(l1 * l2 * l3, 0.4e1 / 0.3e1)
menjadi X * l123_pow_4_3
.
X * pow(l1 * l2 * l3, -0.4e1 / 0.3e1)
menjadi X / l123_pow_4_3
.
Maple memang melewatkan yang sudah jelas.
Misalnya, ada cara yang lebih mudah untuk menulis
(pow(l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * pow(l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
Dengan asumsi bahwa l1
,, l2
dan l3
adalah bilangan real daripada bilangan kompleks, dan bahwa akar pangkat tiga nyata (bukan akar kompleks utama) akan diekstraksi, di atas tereduksi menjadi
2.0/(3.0 * pow(l1 * l2 * l3, 1.0/3.0))
atau
2.0/(3.0 * l123_pow_1_3)
Menggunakan cbrt_l123
alih-alih l123_pow_1_3
, ekspresi buruk dalam pertanyaan tersebut dikurangi menjadi
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);
Selalu periksa ulang, tetapi selalu sederhanakan juga.
Berikut adalah beberapa langkah saya untuk sampai di atas:
// 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);
Jawaban yang salah, sengaja disimpan untuk kerendahan hati
Perhatikan bahwa ini terserang. Itu salah.
Memperbarui
Maple memang melewatkan yang sudah jelas. Misalnya, ada cara yang lebih mudah untuk menulis
(pow (l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * pow (l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
Dengan asumsi bahwa l1
, l2
, danl3
adalah bilangan real daripada bilangan kompleks, dan bahwa akar pangkat tiga yang sebenarnya (bukan akar kompleks utama) akan diekstraksi, di atas tereduksi menjadi nol. Perhitungan nol ini diulang berkali-kali.
Pembaruan kedua
Jika saya telah menyelesaikan matematika dengan benar (tidak ada jaminan bahwa saya telah menyelesaikan matematika dengan benar), ekspresi buruk dalam pertanyaan tersebut berkurang menjadi
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);
Di atas mengasumsikan bahwa l1
, l2
, dan l3
adalah bilangan real positif.
pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
dengan variabel ... Anda perlu melakukan benchmark kode Anda untuk memastikan apakah itu berjalan cepat atau lambat.