Ми намагаємося оптимізувати наш C ++ код, і у нас є наступні матричні обчислення (за допомогою бібліотеки Eigen)
#include<Eigen/Dense>
int main(){
MatrixXd P = MatrixXd::Random(30,30); // a random double 30 x 30 matrix P
MatrixXd M = MatrixXd::Random(30,30); // a random double 30 x 30 matrix M
Matrix<double, 30, 30> I;
I.setIdentity(); // I is an 30 x 30 identity matirx
P = (I-M)*P
return 0;
}
Де вони всі матриці nxn, а I - це тотожна матриця. Ми знайшли переписання вищезгаданого матричного обчислення
P= (I- M)*P
як
P = P-M*P
призводить до швидкості ~ 4-8x в ubuntu Linuxсистема, що використовує компілятор gcc 6.2. Я усвідомлюю той факт, що компілятор може нічого не знати про матрицю ідентичності та про те, що я * P = P, але все одно не може обернути голову навколо того, що робить ефективність настільки сильною. Хто-небудь знає можливі причини, які роблять такі істотні поліпшення?
Відповіді:
1 для відповіді № 1Поперше, I.identity();
не існує. Те, чого ви хочете, теж є I.setIdentity()
, або P = (MatrixXd::Identity(30,30)-M)*P
. Якщо ви використовуєте перший варіант, Eigen, безумовно, повинен зробити повне віднімання 30x30 I
і M
(компілятору буде важко бачити еквівалентність другому виразу). Загалом, це призведе до двох тимчасових (один для різниці, один для продукту).
Якщо ви дійсно використовували I.Identity()
ви викликаєте статичну функцію, як функцію-член, і ваш компілятор повинен принаймні попередити вас про це. Це фактично не буде змінено I
і ви отримаєте неініціалізовані значення в I
, який, ймовірно, включатиме деяке NaN або денормальне значення, обидва можуть бути поганими для продуктивності з плаваючою комою. І, звичайно, ваш результат буде неправильним.
Загалом, я думаю, що найпростіші способи написати свій рівняння є
P -= M*P;
або
MatrixXd Pnew = P - M*P;