MethodImplOptions.InternalCall
Das bedeutet, dass die Methode tatsächlich in der CLR implementiert und in C++ geschrieben ist. Der Just-in-Time-Compiler konsultiert eine Tabelle mit intern implementierten Methoden und kompiliert den Aufruf der C++-Funktion direkt.
Um einen Blick auf den Code zu werfen, ist der Quellcode der CLR erforderlich. Diesen können Sie aus dem SSCLI20-Verteilung . NET 2.0 geschrieben wurde, habe ich die Low-Level-Implementierungen gefunden, wie Math.Pow()
für spätere Versionen der CLR noch weitgehend zutreffend zu sein.
Die Nachschlagetabelle befindet sich in clr/src/vm/ecall.cpp. Der Abschnitt, der für Math.Pow()
sieht so aus:
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()
Die Suche nach "COMDouble" führt Sie zu clr/src/classlibnative/float/comfloat.cpp. Ich erspare Ihnen den Code, schauen Sie ihn sich einfach selbst an. Im Grunde prüft er auf Eckfälle und ruft dann die CRT-Version von pow()
.
Das einzige andere interessante Detail der Implementierung ist das FCIntrinsic-Makro in der Tabelle. Das ist ein Hinweis darauf, dass der Jitter die Funktion als Intrinsic implementieren kann. Mit anderen Worten: Ersetzen Sie den Funktionsaufruf durch eine Gleitkomma-Maschinencode-Anweisung. Dies ist nicht der Fall bei Pow()
gibt es keinen FPU-Befehl für sie. Aber für die anderen einfachen Operationen schon. Bemerkenswert ist, dass dies Fließkomma-Mathematik in C# wesentlich schneller machen kann als den gleichen Code in C++, siehe diese Antwort für den Grund dafür.
Übrigens ist der Quellcode für den CRT auch verfügbar, wenn Sie die Vollversion von Visual Studio im Verzeichnis vc/crt/src haben. Sie stoßen auf die Wand bei pow()
Allerdings hat Microsoft diesen Code von Intel gekauft. Es ist unwahrscheinlich, dass sie es besser machen als die Intel-Ingenieure. Obwohl die Identität meines Highschool-Buches doppelt so schnell war, als ich es ausprobiert habe:
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
Aber es ist kein echter Ersatz, weil es Fehler aus 3 Fließkommaoperationen akkumuliert und nicht mit den seltsamen Domänenproblemen zu tun hat, die Pow() hat. Wie z.B. 0^0 und -Infinity erhöht auf eine beliebige Potenz.