Редактировать сводку
- В моем первоначальном ответе просто отмечалось, что код содержит множество реплицированных вычислений и что многие из степеней включают коэффициент 1/3. Например,
pow(x, 0.1e1/0.3e1)
это то же самое, что и cbrt(x)
.
- Моя вторая редакция была просто неправильной, а третья экстраполировала на эту неправильность. Это то, что заставляет людей бояться изменять результаты, похожие на оракулы, в символьных математических программах, которые начинаются с буквы «М». Я вычеркнул (т.
Е. Вычеркнул ) эти правки и поместил их в конец текущей редакции этого ответа. Однако я не стал их удалять. Я человек. Нам легко ошибиться.
- Мой четвёртый редактировать разработал очень компактное выражение , которое правильно представляет запутанные выражения в вопросе IF параметры
l1
, l2
и l3
положительные действительные числа , а если a
есть ненулевой вещественное число. (Нам еще предстоит получить известие от OP относительно специфики этих коэффициентов. Учитывая характер проблемы, это разумные предположения.)
- Это редактирование пытается ответить на общую проблему, как упростить эти выражения.
Перво-наперво
Я использую Maple для генерации кода C ++, чтобы избежать ошибок.
Maple и Mathematica иногда упускают из виду очевидное. Что еще более важно, пользователи Maple и Mathematica иногда делают ошибки. Замена «часто» или, может быть, даже «почти всегда» вместо «иногда», вероятно, ближе к цели.
Вы могли бы помочь Maple упростить это выражение, рассказав ему о рассматриваемых параметрах. В данном примере я подозреваю, что l1
, l2
и l3
- положительные действительные числа, а a
это ненулевое действительное число. Если это так, скажи ему об этом. Эти символьные математические программы обычно предполагают наличие сложных величин. Ограничение домена позволяет программе делать предположения, которые недопустимы для комплексных чисел.
Как упростить этот большой беспорядок с помощью символьных математических программ (это правка)
Символьные математические программы обычно предоставляют информацию о различных параметрах. Используйте эту способность, особенно если ваша проблема связана с делением или возведением в степень. В примере , под рукой, вы могли бы помочь Maple упростить это выражение, говоря это , что l1
, l2
и l3
являются положительные действительные числа , и что a
не является нулевой реальный номер. Если это так, скажи ему об этом. Эти символьные математические программы обычно предполагают наличие сложных величин. Ограничение домена позволяет программе делать такие предположения, как a x b x = (ab) x . Это только в том случае, если a
и b
являются положительными действительными числами, и если они x
реальны. Не действует в комплексных числах.
В конечном итоге эти программы с символьной математикой следуют алгоритмам. Помогите ему. Попробуйте поиграть с расширением, сбором и упрощением, прежде чем создавать код. В этом случае вы могли бы собрать те термины, которые включают фактор, mu
и те, которые включают фактор K
. Приведение выражения к его «простейшей форме» остается искусством.
Когда вы получаете ужасный беспорядок сгенерированного кода, не принимайте это как истину, к которой вы не должны прикасаться. Попробуйте сами упростить. Посмотрите, что было у символьной математической программы до того, как она сгенерировала код. Посмотрите, как я свел ваше выражение к чему-то более простому и быстрому, и как ответ Уолтера продвинул мой на несколько шагов вперед. Волшебного рецепта нет. Если бы существовал волшебный рецепт, Мейпл применил бы его и дал бы ответ, который дал Уолтер.
О конкретном вопросе
В этом вычислении вы делаете много сложений и вычитаний. Вы можете попасть в серьезные неприятности, если у вас есть условия, которые почти отменяют друг друга. Вы тратите много ресурсов процессора, если у вас есть один термин, который доминирует над другими.
Затем вы тратите много ресурсов ЦП, выполняя повторяющиеся вычисления. Если вы не включили -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);
Всегда перепроверяйте, но всегда упрощайте.
Вот некоторые из моих шагов к достижению вышеизложенного:
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;
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;
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;
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;
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;
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;
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);
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);
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)
переменными ... Вам нужно протестировать свой код, чтобы убедиться, работает он быстро или медленно.