Я не эксперт по этим оптимизациям, но, насколько я понимаю, методы отложенной оценки, о которых вы говорите, работают, определяя арифметические операторы для вашего типа матрицы, так что, например, A+B+C*D
не возвращает матрицу, он возвращает прокси-объект который может преобразовываться в матрицу. Это происходит, когда ему присвоено значение M
, и код преобразования будет вычислять каждую ячейку результирующей матрицы наиболее эффективными способами, которые могут придумать разработчики библиотеки, избегая временных объектов матрицы.
Итак, предположим, что программа содержит M = A + B + C * D;
Если бы вы не сделали ничего умного, кроме как реализовали operator+
обычным способом, используя operator+=
, вы бы получили что-то вроде этого, как только сработает нормальное копирование в стиле C++03:
Matrix tmp1 = C;
tmp1 *= D;
Matrix tmp2 = A;
tmp2 += B;
tmp2 += tmp1;
M = tmp2;
С отложенной оценкой вы можете получить что-то вроде:
for (int i = 0; i < M.rows; ++i) {
for (int j = 0; j < M.cols; ++j) {
/* not necessarily the best matrix multiplication, but serves to illustrate */
c_times_d = 0;
for (int k = 0; k < C.cols; ++k) {
c_times_d += C[i][k] * D[k][j];
}
M[i][j] = A[i][j] + B[i][j] + c_times_d;
}
}
в то время как код «ничего умного» будет выполнять пару отдельных циклов сложения и гораздо больше присваиваний.
Насколько мне известно, семантика перемещения в этом случае мало помогает. Ничто из того, что вы написали, не позволяет нам перейти от A
, B
, C
или D
, поэтому мы получим эквивалент:
Matrix tmp1 = C;
tmp1 *= D;
Matrix tmp2 = A;
tmp2 += B;
tmp2 += std::move(tmp1);
M = std::move(tmp2);
Таким образом, семантика перемещения не помогла ни с чем, кроме последнего бита, где, возможно, версии операторов rvalue лучше, чем обычные. Доступно больше, если вы напишете std::move(A) + std::move(B) + std::move(C) * std::move(D)
, потому что нам не пришлось бы копировать из C
или A
, но я все равно не думаю, что результат будет таким же хорошим, как код с отложенной оценкой.
По сути, семантика перемещения не помогает в некоторых важных частях оптимизации, обеспечиваемой отложенной оценкой:
1) при отложенной оценке промежуточные результаты никогда не должны существовать в виде полных матриц. Семантика перемещения не спасает компилятор от создания полной матрицы A+B
в памяти в какой-то момент.
2) с отложенным вычислением мы можем начать изменять M
до того, как закончим вычисление всего выражения. Семантика перемещения не помогает компилятору переупорядочивать модификации: даже если компилятор достаточно умен, чтобы определить потенциальную возможность, модификации невременных объектов должны храниться в правильном порядке, если существует опасность выбрасывается исключение, потому что если какая-либо часть A + B + C * D
выбрасывается, то M
нужно оставить в том виде, в котором она началась.
person
Steve Jessop
schedule
23.05.2012
A*B+C
шаблон выражения может оптимизировать вычисления, вставляя инструкции FMA и т. д. - person André Caron   schedule 23.05.2012