Оптимизация составного std :: functions - PullRequest
1 голос
/ 21 июля 2011

Можно ли оптимизировать серию "склеенных" std::function с и / или есть какая-либо реализация, которая пытается это сделать?

То, что я имею в виду, легче всего выразить математически: скажем, я хочу сделать std::function, который является функцией функции:

f(x,y,z) = x^2 * y^3 * z^4
g(x,y,z) = f(x,y,z) / (x*y^2)

Есть ли способ для разработчика STL / компилятора оптимизировать удаленные части арифметики, вызывая функциональный объект g, созданный из функционального объекта f?

Это было бы своего рода символическим упрощением функций, но поскольку это std::function, его нужно было бы обнаружить на уровне машины.

Из-за того, что это оптимизация, которая требует времени и, вероятно, не бесплатна (в тактах и ​​/ или памяти), она, вероятно, не разрешена Стандартом? Он опирается очень близко к языку, который обычно запускается через виртуальную машину. (Я думаю, что LLVM здесь больше, чем Java, с оптимизацией времени выполнения).

РЕДАКТИРОВАТЬ: Чтобы сделать обсуждение "более полезным", вот небольшой фрагмент кода (я понимаю, что лямбда не является std::function, но лямбда может быть сохранена в std::function, поэтому предположим, что auto ниже означает std::function<T> с соответствующим T отлично выразит то, что я имел в виду выше):

auto f = [](const double x, const double y, const double z){ return x*x*y*y*y*z*z*z*z; };
auto g = [](const double c, const double y, const double z){ return f(x,y,z)/(x*y*y); };

«Тривиальный» компилятор сделает g эквивалентным

double g(const double x, const double y, const double z){ return x*x*y*y*y*z*z*z*z/(x*y*y); }

Хотя оптимизированный std::function мог бы сделать это (математически и во всех других смыслах правильно!):

double g( const double x, const double y, const double z){ return x*y*z*z*z*z; }

Обратите внимание, что хотя я говорю о математических функциях здесь, аналогичные преобразования могут быть сделаны для функций в общем смысле, но для этого потребуется больше самоанализа, что означает накладные расходы.

Я вижу, что это очень важно при разработке математических и физических симуляций, где общность объединения существующих библиотечных функций в пользовательские функции со всеми обычными математическими упрощениями могла бы стать хорошим методом выразительного, но производительного программного обеспечения для расчетов. .

Ответы [ 2 ]

4 голосов
/ 21 июля 2011

Вот почему вы оставляете оптимизацию компилятору. Они алгебраически эквивалентны, но не эквивалентны из-за неточности FP. Ваши две версии g дадут слегка разные ответы, которые могут быть очень важны, если их вызвать во внутреннем цикле, не говоря уже о поведенческой разнице, если x, y, z было 0.

Во-вторых, поскольку содержимое function неизвестно до времени выполнения, компилятор не сможет выполнить такую ​​оптимизацию, поскольку у него нет нужных ему данных.

1 голос
/ 21 июля 2011

Компилятору разрешено оптимизировать в определенных разрешенных случаях, или если оптимизированный код ведет себя «как если бы», это был неоптимизированный код.

В этом случае не только x или y, равный 0, изменит результаты, но если f переполнится, или типы данных будут с плавающей запятой или пользователь определит, результаты могут измениться в результате такой оптимизации. Таким образом, я подозреваю, что на практике вы никогда не увидите, чтобы это произошло, и придется (если это возможно) составлять комбинированную функцию во время компиляции (предположительно, с использованием шаблонов).

...