c# - 階乗 - Math.Pow()は.NET Frameworkでどのように実装されていますか?
c# 階乗 (2)
私はaを計算するための効率的なアプローチを探していました( a = 2
とb = 50
)。 まず、 Math.Pow()
関数の実装を見てみることにしました。 しかし.NET Reflectorでは、私が見つけたのはこれでした:
[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
public static extern double Pow(double x, double y);
Math.Pow()
関数を呼び出すと、内部で何が起こっているのか見ることができるリソースのいくつかは何ですか?
MethodImplOptions.InternalCall
つまり、このメソッドはC ++で記述されたCLRで実際に実装されています。 ジャストインタイムコンパイラは、内部的に実装されたメソッドを持つテーブルを参照し、C ++関数の呼び出しを直接コンパイルします。
コードを見るには、CLRのソースコードが必要です。 あなたはSSCLI20ディストリビューションからそれを得ることができます。 これは.NET 2.0の時間枠の周りに書かれており、 Math.Pow()
ような低レベルの実装はCLRの後のバージョンでもかなり正確であることがわかりました。
ルックアップテーブルは、clr / src / vm / ecall.cppにあります。 Math.Pow()
関連するセクションは次のようになります:
FCFuncStart(gMathFuncs)
FCIntrinsic("Sin", COMDouble::Sin, CORINFO_INTRINSIC_Sin)
FCIntrinsic("Cos", COMDouble::Cos, CORINFO_INTRINSIC_Cos)
FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt)
FCIntrinsic("Round", COMDouble::Round, CORINFO_INTRINSIC_Round)
FCIntrinsicSig("Abs", &gsig_SM_Flt_RetFlt, COMDouble::AbsFlt, CORINFO_INTRINSIC_Abs)
FCIntrinsicSig("Abs", &gsig_SM_Dbl_RetDbl, COMDouble::AbsDbl, CORINFO_INTRINSIC_Abs)
FCFuncElement("Exp", COMDouble::Exp)
FCFuncElement("Pow", COMDouble::Pow)
// etc..
FCFuncEnd()
"COMDouble"を検索すると、clr / src / classlibnative / float / comfloat.cppに移動します。 私はあなたにコードを惜しまないでしょう、ちょうどあなた自身のために見てください。 基本的にコーナーケースをチェックしてから、CRTのバージョンのpow()
呼び出します。
面白いのは、テーブル内のFCIntrinsicマクロだけです。 これは、ジッタがその関数を組み込み関数として実装するかもしれないというヒントです。 つまり、関数呼び出しを浮動小数点マシンコード命令に置き換えます。 Pow()
には当てはまりませんが、FPU命令はありません。 しかし、確かに他の簡単な操作のために。 注目すべき点は、これがC ++の浮動小数点数計算をC ++の同じコードよりも大幅に高速化できることです。 この理由を理由にチェックしてください。
ちなみに、Visual Studio vc / crt / srcディレクトリのフルバージョンをお持ちの場合は、CRTのソースコードも入手できます。 あなたはpow()
壁に衝突しますが、MicrosoftはそのコードをIntelから購入しました。 インテルのエンジニアよりも優れた仕事をすることはまずありません。 私の高校の本のアイデンティティーは、私が試したときに2倍速かったが、
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
しかし、3つの浮動小数点演算からの誤差を累積し、Pow()が持つ変わった領域の問題に対処していないため、真の代用ではありません。 0 ^ 0と-Infinityのように任意のパワーに上昇。
自由に利用できるCバージョンのpow
が表示されていれば、それはあなたが期待するようなものではありません。 あなたが解決している問題(すなわち、整数を持つもの)は、より単純なものであり、数行のC#コードでべき乗剰余を使って解くことができるので、.NETバージョンを見つけるのにはあまり役に立たないでしょう二乗アルゴリズムによって 。