MethodImplOptions.InternalCall
Cela signifie que la méthode est réellement implémentée dans le CLR, écrite en C ++. Le compilateur juste à temps consulte une table avec des méthodes implémentées en interne et compile l'appel à la fonction C ++ directement.
L'examen du code nécessite le code source du CLR. Vous pouvez l'obtenir auprès de la distribution SSCLI20 . Il a été écrit autour de la période de temps .NET 2.0, j'ai trouvé les implémentations de bas niveau, comme Math.Pow()
étant encore largement précises pour les versions ultérieures du CLR.
La table de recherche se trouve dans clr / src / vm / ecall.cpp. La section qui est pertinente Math.Pow()
ressemble à ceci:
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 recherche de "COMDouble" vous amène à clr / src / classlibnative / float / comfloat.cpp. Je vais vous épargner le code, jetez un œil par vous-même. Il vérifie essentiellement les cas d'angle, puis appelle la version du CRT de pow()
.
Le seul autre détail d'implémentation qui est intéressant est la macro FCIntrinsic dans le tableau. C'est un indice que la gigue peut implémenter la fonction comme intrinsèque. En d'autres termes, remplacez l'appel de fonction par une instruction de code machine à virgule flottante. Ce qui n'est pas le cas Pow()
, il n'y a aucune instruction FPU pour cela. Mais certainement pour les autres opérations simples. Il est à noter que cela peut rendre les mathématiques à virgule flottante en C # beaucoup plus rapides que le même code en C ++, vérifiez cette réponse pour la raison.
Par ailleurs, le code source du CRT est également disponible si vous disposez de la version complète du répertoire Visual Studio vc / crt / src. Vous allez heurter le mur pow()
, Microsoft a acheté ce code auprès d'Intel. Faire un meilleur travail que les ingénieurs Intel est peu probable. Bien que l'identité de mon livre de lycée était deux fois plus rapide lorsque je l'ai essayé:
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
Mais ce n'est pas un vrai substitut car il accumule les erreurs de 3 opérations en virgule flottante et ne traite pas les problèmes de domaine bizarre de Pow (). Comme 0 ^ 0 et -Infinity élevé à n'importe quelle puissance.
InternalCall
avec unextern
modificateur (car ils semblent être en conflit), veuillez voir la question (et les réponses qui en résultent) que j'ai postée à propos de cette même chose.