8

私は、OpenCV、HALCON などを拡張する画像処理ライブラリに取り組んでいます。ライブラリは .NET Framework 3.5 である必要があり、.NET の経験が限られているため、パフォーマンスに関していくつか質問したいと思います。

私は自分自身に適切に説明できないいくつかの特定の事柄に遭遇しました.a)理由とb)ケースに対処するためのベストプラクティスは何ですか.

私の最初の質問は、Math.pow についてです。私はすでにいくつかの回答を StackOverflow で見つけましたが、これは非常によく説明されています (a) が、これについて何をすべきか (b) はわかりません。私のベンチマークプログラムは次のようになります

Stopwatch watch = new Stopwatch();  // from the Diagnostics class
watch.Start();
for (int i = 0; i < 1000000; i++)
    double result = Math.Pow(4,7)   // the function call
watch.Stop()

結果はあまり良くありませんでした (私のコンピューターでは約 300 ミリ秒) (テストを 10 回実行し、平均値を計算しました)。

私の最初のアイデアは、これが静的関数であるためかどうかを確認することでした。だから私は自分のクラスを実装しました

class MyMath
{
    public static double Pow (double x, double y)   //Using some expensive functions to calculate the power
    {
        return Math.Exp(Math.Log(x) * y);
    }

    public static double PowLoop (double x, int y)  // Using Loop
    {
        double res = x;
        for(int i = 1; i < y; i++)
            res *= x;
        return res;
    }

    public static double Pow7 (double x)            // Using inline calls
    {
        return x * x * x * x * x * x * x;
    }
}

私がチェックした 3 番目のことは、Math.Pow(4,7) を 4*4*4*4*4*4*4 で直接置き換えるかどうかでした。

結果は (10 回のテスト実行の平均)

300 ms   Math.Pow(4,7)
356 ms   MyMath.Pow(4,7)    //gives wrong rounded results
264 ms   MyMath.PowLoop(4,7)
 92 ms   MyMath.Pow7(4)
 16 ms   4*4*4*4*4*4*4

現在、私の状況は基本的に次のようになっています。 Pow に Math を使用しないでください。私の唯一の問題はそれです...私は本当に自分のMathクラスを実装する必要がありますか? 累乗関数のためだけに独自のクラスを実装するのは、どういうわけか効果がないようです。(ちなみに、PowLoop と Pow7 はリリース ビルドでさらに 25% 高速ですが、Math.Pow はそうではありません)。

だから私の最後の質問は

a)Math.Powをまったく使用しない場合(ただし、分数の場合はおそらく)間違っています(これはなんとなく悲しくなります)。

b) 最適化するコードがある場合、そのような数学演算をすべて直接記述していますか?

c)数学演算用のより高速な(オープンソース^^)ライブラリがすでにあるかもしれません

d)私の質問のソースは基本的に次のとおりです。.NET Framework自体がすでに非常に最適化されたコードを提供し、そのような基本的な操作の結果をコンパイルすると仮定しました-それがMath-Classであろうと配列の処理であろうと、私は少し驚きました私は自分のコードを書くことで得をします。C#を直接信頼できないC#で、他に一般的な「フィールド」または何か他のものがありますか?

4

3 に答える 3

5

覚えておくべき2つのこと:

  1. おそらく、このコードを最適化する必要はありません。1秒以内に関数を100万回呼び出しました。これは本当にあなたのプログラムに大きな問題を引き起こすのでしょうか?

  2. Math.Powとにかくおそらくかなり最適です。推測では、低水準言語で記述された適切な数値ライブラリを呼び出すことになります。つまり、桁違いの増加を期待するべきではありません。

  3. 数値プログラミングはあなたが思っているより難しいです。あなたが計算方法を知っていると思うアルゴリズムでさえ、そのように計算されていません。たとえば、平均を計算するときは、単に数値を合計して、数で割ってはいけません。(最新の数値ライブラリは、2パスルーチンを使用して浮動小数点エラーを修正します。)

とはいえ、間違いなく最適化する必要があると判断した場合は、浮動小数点値ではなく整数を使用するか、これを別の数値ライブラリにアウトソーシングすることを検討してください。

于 2011-03-04T10:40:14.063 に答える
2

まず、整数演算は浮動小数点演算よりもはるかに高速です。浮動小数点値が必要ない場合は、浮動小数点データ型を使用しないでください。これは一般に、どのプログラミング言語にも当てはまります。

第二に、あなたが述べたように、Math.Pow実数を処理できます。単純なループよりもはるかに複雑なアルゴリズムを使用します。単にループするより遅いのも不思議ではありません。ループをなくして n 回の乗算だけを行うと、ループを設定するオーバーヘッドも削減され、ループが高速化されます。ただし、ループを使用しない場合は、指数の値を事前に知っておく必要があります。実行時に提供することはできません。

理由はよくわかりませんがMath.ExpMath.Logより高速です。しかし、 を使用するMath.Logと、負の値のべき乗を見つけることができません。

基本的intには高速であり、ループを回避することで余分なオーバーヘッドを回避できます。ただし、それらを選択すると、ある程度の柔軟性が失われます。しかし、整数だけが必要な場合は実数を避けるのが一般的には良い考えですが、この場合、カスタム関数が既に存在する場合にそれをコーディングするのは少し多すぎるように思えます。

あなたが自問しなければならない質問は、これが価値があるかどうかです. Math.Pow実際にプログラムの速度が低下していますか? いずれにせよ、Math.Powあなたの言語に既にバンドルされている は、多くの場合、最速またはそれに非常に近いものです。本当に汎用的な (つまり、整数、正の値などに限定されない) 別の実装を作成したい場合は、デフォルトの実装で使用されているのと同じアルゴリズムを使用することになるでしょう。

于 2011-03-04T10:32:54.173 に答える
0

1 行のコードを何百万回も反復することについて話している場合、明らかに細部のすべてが違いを生みます。

Math.Pow() は、手動の 4*4...*4 の例よりも大幅に遅くなる関数呼び出しです。

標準の Math クラスよりも最適化されたものを作成できるかどうかは疑わしいため、独自のクラスを作成しないでください。

于 2011-03-04T10:22:05.790 に答える