1. ホーム
  2. c#

[解決済み】.NET FrameworkでMath.Pow()はどのように実装されていますか?

2022-03-24 02:43:45

質問

を計算するための効率的な方法を探していました。 b (例えば a = 2b = 50 ). 手始めに、私は Math.Pow() 関数を使用します。しかし .NETリフレクター は、これしか見つかりませんでした。

[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++の同じコードよりも大幅に高速化されることです。 この回答 はその理由です。

ちなみに、CRTのソースコードも、Visual Studioのフルバージョン vc/crt/srcディレクトリがあれば、入手可能です。で壁にぶつかります。 pow() でも、そのコードはマイクロソフトがインテルから買い取ったものなんですよ。しかし、マイクロソフトはインテルからそのコードを購入した。インテルのエンジニアより良い仕事をすることはあり得ない。 高校生の本のIDは、試したところ2倍速かったのですが。

public static double FasterPow(double x, double y) {
    return Math.Exp(y * Math.Log(x));
}

しかし、3回の浮動小数点演算による誤差を蓄積し、Pow()が持つ変な領域の問題を扱わないので、真の代用品とは言えません。 0^0や-Infinityの任意の累乗のような。