По методике шаблонов выражений матричное выражение типа
D = A*B+sin(C)+3.;
с точки зрения производительности вычислений в значительной степени эквивалентен рукописному for
петля.
Теперь предположим, что у меня есть следующие два выражения
D = A*B+sin(C)+3.;
F = D*E;
cout << F << "\n";
В «классической» реализации по шаблонам выражений производительность вычислений будет почти такой же, как у двух for
петли в последовательности. Это потому, что выражения оцениваются сразу после =
операторы встречаются.
Мой вопрос: есть ли метод (например, с использованием заполнителей?), Чтобы признать, что значения D
на самом деле не используются, и что представляющие интерес ценности являются единственными элементами F
, так что только выражение
F = E*(A*B+sin(C)+3.);
оценивается, и вся производительность эквивалентна производительности одного for
цикл?
Конечно, такая гипотетическая техника также должна быть в состоянии вернуться обратно, чтобы оценить выражение
D = A*B+sin(C)+3.;
если позже в коде значения D
необходимы.
Спасибо заранее за любую помощь.
РЕДАКТИРОВАТЬ: Результаты экспериментов решение, предложенное Евгением
Оригинальная инструкция:
Result D=A*B-sin(C)+3.;
Время вычислений: 32 мс
Инструкция в два этапа:
Result Intermediate=A*B;
Result D=Intermediate-sin(C)+3.;
Время вычислений: 43мс
Решение с auto
:
auto&& Intermediate=A*B;
Result D=Intermediate-sin(C)+3.;
Время вычислений: 32мс.
В заключение, auto&&
Позволяет восстановить исходное время вычислений в случае одной команды.
РЕДАКТИРОВАТЬ: Обобщение соответствующих ссылок, следуя предложениям Евгения
Универсальные ссылки на C ++ 11
C ++ и последующий 2012 год: Скотт Мейерс — Универсальные ссылки на C ++ 11
Оценка шаблон выражения обычно происходит, когда вы сохраняете результат в некоторых специальный типа как:
Result D = A*B+sin(C)+3.;
Тип результата выражения:
A*B+sin(C)+3.
не является Результат, но это то, что можно конвертировать в Результат. И оценка происходит во время такой конверсии.
Мой вопрос: есть ли метод (например, использование заполнителей?), Чтобы признать, что значения D на самом деле не используются
Такой вид «трансформации»:
Result D = A*B+sin(C)+3.;
Result F = D*E;
в
Result F = (A*B+sin(C)+3.)*E;
Возможно, когда вы не оцениваете D. Чтобы сделать это, как правило, вы должны захватить D, как это реально, выражение тип. Например, с помощью авто:
auto &&D = A*B+sin(C)+3.;
Result F = D*E;
Тем не менее, вы должны быть осторожны — иногда шаблон выражения захватывает ссылки на его операнды, и если у вас есть некоторые Rvalue который истекает после его выражения:
auto &&D = A*get_large_rvalue();
// At this point, result of **get_large_rvalue** is destructed
// And D has expiried reference
Result F = D*E;
куда get_large_rvalue является:
LargeMatrix get_large_rvalue();
Это результат Rvalue, истекает в конце полного выражения, когда get_large_rvalue назывался. Если что-то в выражении будет хранить указатель / ссылку на него (для последующей оценки), и вы будете «откладывать» оценку — указатель / ссылка переживут указанный / ссылочный объект.
Чтобы предотвратить это, вы должны сделать:
auto &&intermediate = get_large_rvalue(); // it would live till the end of scope
auto &&D = A*intermediate ;
Result F = D*E;
Я не знаком с C ++ 11, но, как я понимаю, auto просит компилятор определить тип переменной по ее инициализации
Да, точно. Это называется Тип Вывод / Дедукция.
В C ++ 98/03 было приведение типа только для шаблонных функций, в C ++ 11 есть авто.
Знаете ли вы, как CUDA и C ++ 11 взаимодействуют друг с другом?
Я не использовал CUDA (хотя я использовал OpenCL), но я думаю, что не будет никаких проблем в хозяин код с C ++ 11. Возможно, некоторые функции C ++ 11 не поддерживаются устройство код, но для вашей цели — вам нужно авто только в хозяин код
Наконец, есть ли возможность только с C ++?
Вы имеете в виду pre-C ++ 11? То есть C ++ 98 / C ++ 03?
Да, это возможно, но у него больше синтаксического шума, возможно, это будет причиной для его отклонения:
// somehwhere
{
use_D(A*B+sin(C)+3.);
}
// ...
template<typename Expression>
void use_D(Expression D) // depending on your expression template library
// it may be better to use (const Expression &e)
{
Result F = D*E;
}
Я сейчас использую CUDA / Visual Studio 2010 под Windows. Не могли бы вы порекомендовать компилятору / набору инструментов / среде для обеих ОС использовать C ++ 11 в рамках моих интересов (GPGPU и CUDA, вы знаете, что-нибудь)
MSVC 2010 поддерживает некоторые части C ++ 11. В частности это поддерживает авто. Так что, если вам нужно только авто из C ++ 11 — MSVC2010 в порядке.
Но если вы можете использовать MSVC2012 — я бы порекомендовал придерживаться его — он имеет гораздо лучшую поддержку C ++ 11.
Кроме того, трюк авто &&промежуточный = get_large_rvalue (); кажется не «прозрачным» для стороннего пользователя (который не должен знать о такой проблеме). Я прав? Любая альтернатива?
Если шаблон выражения хранит ссылки на некоторые значения, и вы откладываете его оценку. Вы должны быть уверены, что все его ссылки живы на месте оценки. Используйте любой метод, который вы хотите — это можно сделать без авто, например:
LargeMatrix temp = get_large_rvalue();
Или, может быть, даже глобальная / статическая переменная (менее предпочтительный метод).
Последний комментарий / вопрос: использовать авто &&D = A * B + sin (C) +3 .; кажется, что я должен перегрузить оператор = для присваиваний между двумя выражениями, верно?
Нет, такая форма не требует ни оператора копирования / перемещения, ни конструктора копирования / перемещения.
По сути, он просто называет временное значение и продлевает срок его службы до конца области действия. Проверьте это ТАК.
Но, если бы вы использовали другую форму:
auto D = A*B+sin(C)+3.;
В таком случае для компиляции может потребоваться конструктор копирования / перемещения / преобразования (хотя фактическая копия может быть оптимизирована компилятором с помощью Копировать Ellision)
Кроме того, переключение между использованием auto (для промежуточных выражений) и Result to force вычисления кажется непрозрачным для стороннего пользователя. Любая альтернатива?
Я не уверен, есть ли альтернатива. Это по природе шаблонов выражений. Пока вы используете их в выражениях — они возвращают некоторые внутренние промежуточные типы, но когда вы сохраняете какой-то «специальный» тип — оценка запускается.
В C ++ 11 вы можете использовать auto
auto D = A*B+sin(C)+3.;
при условии, что вы используете шаблоны выражений, тип D будет <some template type which represents an expression>
,
Теперь вы должны использовать это осторожно, потому что вы экономите часть памяти (нет необходимости выделять место для матрицы), но в зависимости от того, как вы ее используете, это может быть не лучшим.
Подумать о
F = D * E
Элемент D [i] [j] необходимо многократно «посещать» при вычислении D * E (фактически n раз, где n — размер матриц). Если D — тип с простой матрицей, это не проблема. Если D является выражением, вы оцениваете его много, много раз.
На контрай, занимаюсь
F = D + E
Это хорошо.
Подумайте об этом: вы не можете написать F = E*(A*B+sin(C)+3.);
используя только два вложенных цикла.