2011-09-14 12 views
2

私は.NETに移植されたExcelのBETAINV機能を持っていることについて質問を:BetaInv function in SQL Server.NET数学計算公演

は、今私は、純粋な依存少ないC#コードでその関数を記述するために管理し、私はよりも、同じ結果を得ますかMS Excelの最大6桁または7桁のコンマの後、結果は正常ですが、問題はそのようなコードがSQL CLR関数に埋め込まれており、ストアドプロシージャから何千もの時間が呼び出され、プロシージャ全体が約50その機能を使用するかどうかを30秒から1分まで遅くすることができます。

ここにいくつかのコードがありますが、深い分析を求めているわけではありませんが、この計算を行っているところで大きなパフォーマンス上の問題がある人はいますか?ダブルスの代わりに他のデータ型を使用するのと同じように...?

private static double betacf(double a, double b, double x) 
     { 
      int m, m2; 
      double aa, c, d, del, h, qab, qam, qap; 

      qab = a + b; 
      qap = a + 1.0; 
      qam = a - 1.0; 

      c = 1.0; // First step of Lentz’s method. 

      d = 1.0 - qab * x/qap; 

      if (System.Math.Abs(d) < FPMIN) 
      { 
       d = FPMIN; 
      } 

      d = 1.0/d; 
      h = d; 

      for (m = 1; m <= MAXIT; ++m) 
      { 
       m2 = 2 * m; 
       aa = m * (b - m) * x/((qam + m2) * (a + m2)); 
       d = 1.0 + aa * d; //One step (the even one) of the recurrence. 

       if (System.Math.Abs(d) < FPMIN) 
       { 
        d = FPMIN; 
       } 

       c = 1.0 + aa/c; 

       if (System.Math.Abs(c) < FPMIN) 
       { 
        c = FPMIN; 
       } 

       d = 1.0/d; 
       h *= d * c; 

       aa = -(a + m) * (qab + m) * x/((a + m2) * (qap + m2)); 
       d = 1.0 + aa * d; // Next step of the recurrence (the odd one). 

       if (System.Math.Abs(d) < FPMIN) 
       { 
        d = FPMIN; 
       } 

       c = 1.0 + aa/c; 

       if (System.Math.Abs(c) < FPMIN) 
       { 
        c = FPMIN; 
       } 

       d = 1.0/d; 
       del = d * c; 
       h *= del; 

       if (System.Math.Abs(del - 1.0) < EPS) 
       { 
        // Are we done? 
        break; 
       } 
      } 

      if (m > MAXIT) 
      { 
       return 0; 
      } 
      else 
      { 
       return h; 
      } 
     } 

     private static double gammln(double xx) 
     { 
      double x, y, tmp, ser; 

      double[] cof = new double[] { 76.180091729471457, -86.505320329416776, 24.014098240830911, -1.231739572450155, 0.001208650973866179, -0.000005395239384953 }; 

      y = xx; 
      x = xx; 
      tmp = x + 5.5; 
      tmp -= (x + 0.5) * System.Math.Log(tmp); 

      ser = 1.0000000001900149; 

      for (int j = 0; j <= 5; ++j) 
      { 
       y += 1; 
       ser += cof[j]/y; 
      } 

      return -tmp + System.Math.Log(2.5066282746310007 * ser/x); 
     } 

答えて

3

私にとって際立っていて、通常はパフォーマンスが低下するのは、メモリ割り当てだけです。 gammlnがどれくらい頻繁に呼び出されたか分かりませんが、double[] cof = new double[] {}を静的な1回のみの割り当てに移動したい場合があります。

+0

これを試してみてください。ありがとう:)) –

+0

クール、56秒から39秒に下がって、静的配列も読み取り専用でなければならない、またはSQL Serverがアセンブリのインポート/作成に不平を言う。どうもありがとう! –

0

通常はダブルが最適です。特にMathの機能は倍になります。残念ながら、私はあなたのコードを改善することはできません。

ルックアップテーブルを使用して、反復の最初の推定値をより正確に求めることは可能かもしれませんが、私はあなたのやっていることの背後にある数学を知らないので、場合。明らかに、より大きなイプシロンが性能を向上させる。したがって、あなたの正確な要求を満たしながら、できるだけ大きなものを選んでください。

同じパラメータで関数が繰り返し呼び出された場合、結果をキャッシュすることができます。

奇妙に見えるものは、c、d、...の小さい値を強制的にFPMINに設定する方法です。私の本能は、これが次善のステップサイズにつながるかもしれないということです。

+0

残念ながら、私たちはイプシロンを変更することはできません。入力パラメータはランダムで、常に異なっています。私はSQL CLR関数を変更して、入力パラメータの配列に対して動作し、その結果をSQLの結果テーブルに何らかの形で結合するテーブルとして返すことができないかどうかはわかりません。 SQL関数はスカラーパラメータで数千回ではなくすべてのデータで一回使用しています...しかし、代替案をコーディングする際にはいくらかの努力が必要となり、利点がわかりません...とにかく見ていただきありがとうございます:) –

0

jループはgammlnに展開されていますが、ほとんど違いはありません。

純粋なT-SQLで書き直すのは、使用するすべてのものがあるからです。+ - */abs logがすべて利用可能です。

+3

こんにちは、私は記事でこのテキストを見つけたと同じ考えをしていました。CLR関数は、Transact-SQLのユーザー定義関数よりも早い呼び出しパスのメリットがあります。さらに、マネージコードは、プロシージャコード、計算、および文字列操作に関して、Transact-SQLに比べて決定的なパフォーマンス上の利点をもたらします。コンピューティング集約型で、データアクセスを実行しないCLR関数は、マネージコードで記述する方が優れています。ただし、Transact-SQL関数はCLR統合よりも効率的にデータアクセスを実行します。 http://msdn.microsoft.com/en-us/library/ms131075.aspx ... –