MethodImplOptions.InternalCall
Ciò significa che il metodo è effettivamente implementato nel CLR, scritto in C ++. Il compilatore just-in-time consulta una tabella con metodi implementati internamente e compila direttamente la chiamata alla funzione C ++.
Uno sguardo al codice richiede il codice sorgente per il CLR. Puoi ottenerlo dalla distribuzione SSCLI20 . È stato scritto intorno al lasso di tempo di .NET 2.0, ho trovato le implementazioni di basso livello, come se Math.Pow()
fossero ancora in gran parte accurate per le versioni successive del CLR.
La tabella di ricerca si trova in clr / src / vm / ecall.cpp. La sezione pertinente Math.Pow()
è simile alla seguente:
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()
La ricerca di "COMDouble" ti porta a clr / src / classlibnative / float / comfloat.cpp. Ti risparmierò il codice, dai solo un'occhiata. Fondamentalmente controlla la presenza di casi angolari, quindi chiama la versione di CRT di pow()
.
L'unico altro dettaglio di implementazione interessante è la macro FCIntrinsic nella tabella. Questo è un suggerimento che il jitter può implementare la funzione come intrinseca. In altre parole, sostituire la chiamata di funzione con un'istruzione di codice macchina a virgola mobile. Non è questo il caso Pow()
, non ci sono istruzioni FPU per questo. Ma certamente per le altre semplici operazioni. Notevole è che questo può rendere la matematica in virgola mobile in C # sostanzialmente più veloce dello stesso codice in C ++, controlla questa risposta per il motivo.
A proposito, il codice sorgente per CRT è disponibile anche se si dispone della versione completa della directory vc / crt / src di Visual Studio. Colpirai pow()
comunque, Microsoft ha acquistato quel codice da Intel. Fare un lavoro migliore degli ingegneri Intel è improbabile. Anche se l'identità del mio libro del liceo era due volte più veloce quando l'ho provato:
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
Ma non è un vero sostituto perché accumula errori da 3 operazioni in virgola mobile e non affronta i problemi del dominio strano che Pow () ha. Come 0 ^ 0 e -Infinity elevato a qualsiasi potenza.
InternalCall
con unextern
modificatore (poiché sembrano essere in conflitto), vedi la domanda (e le risposte risultanti) che ho pubblicato su questa stessa cosa.