1

プログラム内で使用するためにいくつかの数学関数を作成しましたが、それらは非常に頻繁に使用されます。a) ロジックが改善されているかどうか、b) これを行うためのより良い方法があるかどうかを確認するために、コードを提供したいと思います。必要に応じてインクルードされるヘッダー ファイルです。

私は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_ */
4

3 に答える 3

1

さて、私はいくつかの改善点を見つけました、

  1. std::vector は const 参照または参照で渡す必要があります。

  2. これらの機能のいくつかを確認する必要がありinputs.size()ます。

  3. weightValueVector参照をパラメーターとして取得し、その値を適切に変更することを提供すると、便利で高速になります。

于 2013-10-11T23:34:19.960 に答える
1
  1. おそらく、速度と開発時間の両方で最大のメリットは、車輪を再発明する代わりに、既存の線形代数ライブラリを使用することです。

  2. マシンのアーキテクチャに合わせて調整されたBLASLAPACKを使用します。特に、マシンで使用可能なベクトル命令とキャッシュ サイズは、パフォーマンスに大きな影響を与えます。

  3. ベクトルが十分に小さい場合は、それらをスタックに割り当てることでパフォーマンスが大幅に向上する可能性があります。今、それらをヒープに割り当てています。

  4. テンプレートのメタプログラミング手法を使用すると、コンパイル時に多くの一時的なループや不要なループを排除できます。ここでウィキペディアの例を繰り返すには:

    where はスカラー でありVec x = alpha*(u - v);、は であるとします。 alphauvVecs

    実行している方法で実装すると、少なくとも 2 つの一時ベクトル (1 つはu-vとの乗算用alpha)2 つのメモリを通過するコスト (2 つまたは 3 つのループ: 1 つはu-v、1 つは乗算用) が必要になります。とalpha、最適化されていない場合は割り当て用にもう 1 つ)。

    テンプレートのメタプログラミングを行うVec x = alpha*(u - v);と、一時的なものがない単一のループに要約され、それが得られる最高のものです。より複雑な式ではゲインがさらに大きくなります。

    現時点ではこれらの操作はありませんが、必要になるのは時間の問題だと思います (weightValueVector()は目安です)。

もちろん、線形代数ライブラリを使用する場合は、これらのことを知ったり心配したりする必要はありませんが、代わりにアプリケーションに集中して、非常に高速なコードを取得できます。

于 2013-10-12T11:36:25.193 に答える
1

すでに提供されている回答に加えて
maxInVec関数内:
- ゼロ初期化- 以上double max
をお勧めsize_t varunsigned int var = 0
ます。サイズが事前にわかっている場合は、ベクトルに使用reserveして、いくつかのことを行うときにメモリの再割り当てを避けることもできます。push_back

于 2013-10-12T00:44:00.117 に答える