Я разрабатываю некоторые инженерные модели. Это включает в себя реализацию некоторых длинных уравнений, таких как это уравнение, для вычисления напряжения в материале, подобном резине:
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;
Я использую Maple для генерации кода на С++, чтобы избежать ошибок (и сэкономить время с утомительной алгеброй). Поскольку этот код выполняется тысячи (если не миллионы) раз, производительность является проблемой. К сожалению, математика только упрощает до сих пор; длинные уравнения неизбежны.
Какой подход можно использовать для оптимизации этой реализации? Я ищу стратегии высокого уровня, которые я должен применять при реализации таких уравнений, а не обязательно конкретные оптимизации для приведенного выше примера.
Я компилирую с помощью g++ с --enable-optimize=-O3
.
Update:
Я знаю, что много повторяющихся выражений, я исхожу из предположения, что компилятор справится с ними; мои тесты пока предлагают.
l1, l2, l3, mu, a, K
- все положительные действительные числа (не ноль).
Я заменил l1*l2*l3
эквивалентной переменной: J
. Это помогло повысить производительность.
Замена pow(x, 0.1e1/0.3e1)
на cbrt(x)
была хорошим предложением.
Это будет выполняться на процессорах. В ближайшем будущем это, скорее всего, будет работать лучше на графических процессорах, но пока этот параметр недоступен.