Улучшение класса математической функции для скорости 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 ответа

Решение
  1. Возможно, самым большим выигрышем как в скорости, так и во времени разработки было бы использование существующей библиотеки линейной алгебры вместо повторного изобретения колеса, см.

  2. Используйте BLAS и LAPACK, которые настроены на архитектуру вашей машины. В частности, векторные инструкции, доступные на вашем компьютере, и размеры кэша оказывают ОГРОМНОЕ влияние на производительность.

  3. Если ваши векторы достаточно малы, вы можете получить значительный выигрыш в производительности, разместив их в стеке. Теперь вы размещаете их в куче.

  4. Используя методы метапрограммирования шаблонов, вы можете устранить многие временные и ненужные циклы во время компиляции. Чтобы повторить пример Википедии здесь:

    Скажи у тебя 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

Ну, я заметил несколько улучшений,

  1. std:: vector должен быть передан константной ссылкой или ссылкой.

  2. вам нужно проверить inputs.size() для некоторых из этих функций.

  3. было бы полезно и быстрее предложить weightValueVector для принятия ссылки в качестве параметра и изменения его значений на месте.

Другие вопросы по тегам