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.
Jeter un œil au code nécessite le code source du CLR. Vous pouvez l'obtenir à partir de la distribution SSCLI20. Il a été écrit autour de la période de temps de .NET 2.0, j'ai trouvé que les implémentations de bas niveau, comme Math.Pow()
, sont 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 concerne Math.Pow()
ressemble à cela :
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()
Rechercher "COMDouble" vous emmène à clr/src/classlibnative/float/comfloat.cpp. Je vous épargne le code, jetez-y un coup d'œil par vous-même. Fondamentalement, il vérifie les cas particuliers, puis appelle la version CRT de pow()
.
Le seul autre détail d'implémentation intéressant est le macro FCIntrinsic dans la table. C'est un indice que le jitter peut implémenter la fonction comme un intrinsèque. En d'autres termes, substituer l'appel de fonction par une instruction de code machine en virgule flottante. Ce n'est pas le cas pour Pow()
, il n'y a pas d'instruction FPU pour cela. Mais certainement pour les autres opérations simples. À noter que cela peut rendre les mathématiques en virgule flottante en C# sensiblement plus rapides que le même code en C++, consultez cette réponse pour connaître la raison.
En passant, le code source pour le CRT est également disponible si vous avez la version complète du répertoire vc/crt/src de Visual Studio. Vous atteindrez cependant une impasse sur pow()
, Microsoft a acheté ce code à Intel. Faire un meilleur travail que les ingénieurs d'Intel est peu probable. Bien que l'identité de mon livre de lycée était deux fois plus rapide lorsque j'ai essayé :
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
Mais ce n'est pas un véritable substitut car cela accumule des erreurs à partir de 3 opérations en virgule flottante et ne traite pas les problèmes de domaine bizarres que Pow() a. Comme 0^0 et -Infinity élevé à n'importe quelle puissance.
17 votes
Tout comme information, si vous êtes confus au sujet de l'ensemble
InternalCall
avec un modificateurextern
(comme ils semblent être en conflit), veuillez consulter la question (et les réponses qui en découlent) que j'ai postée à propos de cette même chose.7 votes
Pour une opération
2^x
, six
est un entier, le résultat est une opération de décalage. Vous pourriez donc construire le résultat en utilisant une mantisse de2
et un exposant dex
.0 votes
@SurajJain votre commentaire est en fait une question que vous devez poster séparément.
0 votes
@SurajJain Je suis d'accord avec toi. Je ne suis pas un modérateur donc je ne peux rien faire ici. Peut-être que la question concernant les votes négatifs peut être posée sur meta.stackoverflow.com