Улучшение класса математической функции для скорости C++
Я написал несколько математических функций для использования в моей программе, они будут очень интенсивно использоваться. Я хотел бы предложить код, чтобы увидеть, если а) есть ли улучшения логики, и б) есть ли лучший способ сделать что-либо из этого. Это заголовочный файл, который включается при необходимости.
Я не компилирую для C++11, поэтому, пожалуйста, помните об этом. - Я также знаю, что rootDouble для отрицательных чисел не является математически правильным.
Я думаю, что первое, что может возникнуть, - это преобразовать входные данные вектора для передачи по ссылке, комментарии по этому поводу приветствуются.
С точки зрения того, что я принимаю ответ, я хотел бы знать, что и как можно улучшить для ускорения этих функций.
++ Я написал это довольно быстро, надеюсь, я не оставил никаких смущающих ошибок внутри!
#ifndef MATHSFUNCTIONS_H_
#define MATHSFUNCTIONS_H_
#include <algorithm>
#include <vector>
#include <numeric>
#include <cmath>
class MathsFunctions {
public:
MathsFunctions();
virtual ~MathsFunctions();
inline static double squareDouble(double input) {
return input * input;
}
inline static double rootDouble(double input) {
if (input == 0.0) {
return 0.0;
} else if ( input < 0.0) {
input = flipDouble(input);
input = sqrt(input);
return flipDouble(input);
}
return sqrt(input);
}
inline static double flipDouble(double input) {
return input * -1;
}
inline static double rangeInVec(std::vector<double> inputs) {
return maxInVec(inputs) - minInVec(inputs);
}
inline static double stdDevInVec(std::vector<double> inputs) {
if (inputs.size() < 2) {return 0.0;}
double mean = meanInVec(inputs);
double sq_sum = std::inner_product(inputs.begin(), inputs.end(), inputs.begin(), 0.0);
return std::sqrt(sq_sum / inputs.size() - mean * mean);
}
inline static double meanInVec(std::vector<double> inputs) {
double sum = std::accumulate(inputs.begin(), inputs.end(), 0.0);
return sum / inputs.size();
}
inline static double sumOfVec(std::vector<double> inputs) {
double total = 0.0;
for (unsigned int var = 0; var < inputs.size(); ++var) {
total += inputs[var];
}
return total;
}
inline static double maxInVec(std::vector<double> inputs) {
bool first = true;
double max;
for (unsigned int var = 0; var < inputs.size(); ++var) {
if (first) {
max = inputs[var];
first = false;
} else {
if (inputs[var] > max) {
max = inputs[var];
}
}
}
return max;
}
inline static double minInVec(std::vector<double> inputs) {
bool first = true;
double min;
for (unsigned int var = 0; var < inputs.size(); ++var) {
if (first) {
min = inputs[var];
first = false;
} else {
if (inputs[var] < min) {
min = inputs[var];
}
}
}
return min;
}
inline static std::vector<double> weightValueVector(std::vector<double> inputs,std::vector<double> weights) {
std::vector<double> results;
for (unsigned x = 0; x < inputs.size(); ++x) {
results.push_back(inputs[x] * weights[x]);
}
return results;
}
};
#endif /* MATHSFUNCTIONS_H_ */
3 ответа
Возможно, самым большим выигрышем как в скорости, так и во времени разработки было бы использование существующей библиотеки линейной алгебры вместо повторного изобретения колеса, см.
Используйте BLAS и LAPACK, которые настроены на архитектуру вашей машины. В частности, векторные инструкции, доступные на вашем компьютере, и размеры кэша оказывают ОГРОМНОЕ влияние на производительность.
Если ваши векторы достаточно малы, вы можете получить значительный выигрыш в производительности, разместив их в стеке. Теперь вы размещаете их в куче.
Используя методы метапрограммирования шаблонов, вы можете устранить многие временные и ненужные циклы во время компиляции. Чтобы повторить пример Википедии здесь:
Скажи у тебя
Vec x = alpha*(u - v);
гдеalpha
это скаляр иu
а такжеv
являютсяVecs
,Если вы реализуете его так, как вы это делаете, это обойдется вам как минимум в 2 временных вектора (один для
u-v
и один для умножения сalpha
) и 2, проходящие через память (2 или 3 цикла: один дляu-v
один для умножения наalpha
и еще один для назначения, если это не оптимизировано далеко).Если вы делаете шаблонное метапрограммирование,
Vec x = alpha*(u - v);
будет сводиться к одной петле без временных, и это лучшее, что вы можете получить. Прибыль становится еще больше с более сложными выражениями.На данный момент у вас нет этих операций, но я думаю, что это только вопрос времени, что они вам понадобятся (
weightValueVector()
это указание).
Конечно, если вы используете библиотеку линейной алгебры, вам не нужно знать / беспокоиться о любом из них, но вместо этого вы можете сконцентрироваться на своем приложении и получить потрясающий быстрый код.
Наверху ответов уже предоставлено:
в maxInVec
функция:
- ноль инициализировать double max
- Я бы посоветовал size_t var
над unsigned int var = 0
Вы также можете использовать reserve
для вашего вектора, когда вы знаете размер заранее, чтобы избежать перераспределения памяти при выполнении нескольких push_back
Ну, я заметил несколько улучшений,
std:: vector должен быть передан константной ссылкой или ссылкой.
вам нужно проверить
inputs.size()
для некоторых из этих функций.было бы полезно и быстрее предложить
weightValueVector
для принятия ссылки в качестве параметра и изменения его значений на месте.