MethodImplOptions.InternalCall
Oznacza to, że metoda jest faktycznie zaimplementowana w CLR, napisanym w C ++. Kompilator just-in-time konsultuje tabelę z wewnętrznie zaimplementowanymi metodami i bezpośrednio kompiluje wywołanie funkcji C ++.
Spojrzenie na kod wymaga kodu źródłowego dla CLR. Możesz to uzyskać z dystrybucji SSCLI20 . Został napisany wokół ramy czasowej .NET 2.0. Znalazłem implementacje niskiego poziomu, które lubią Math.Pow()
być w dużej mierze dokładne w późniejszych wersjach CLR.
Tabela odnośników znajduje się w clr / src / vm / ecall.cpp. Sekcja istotna dla Math.Pow()
wygląda następująco:
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()
Wyszukiwanie „COMDouble” prowadzi do clr / src / classlibnative / float / comfloat.cpp. Oszczędzę ci kodu, po prostu sprawdź. Zasadniczo sprawdza przypadki narożne, a następnie wywołuje wersję CRT pow()
.
Jedynym interesującym szczegółem implementacji jest makro FCIntrinsic w tabeli. To wskazówka, że fluktuacja może implementować tę funkcję jako wewnętrzną. Innymi słowy, zastąp funkcję wywołania zmiennoprzecinkową instrukcją kodu maszynowego. To nie jest przypadek Pow()
, nie ma instrukcji FPU. Ale z pewnością w przypadku innych prostych operacji. Warto zauważyć, że dzięki temu matematyka zmiennoprzecinkowa w języku C # jest znacznie szybsza niż ten sam kod w języku C ++, sprawdź tę odpowiedź z tego powodu.
Nawiasem mówiąc, kod źródłowy dla CRT jest również dostępny, jeśli masz pełną wersję katalogu Visual Studio vc / crt / src. Trafisz jednak na mur pow()
, Microsoft kupił ten kod od Intela. Wykonywanie lepszej pracy niż inżynierowie Intela jest mało prawdopodobne. Chociaż tożsamość mojej licealnej książki była dwukrotnie szybsza, gdy jej spróbowałem:
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
Ale nie jest to prawdziwy substytut, ponieważ kumuluje błąd z 3 operacji zmiennoprzecinkowych i nie radzi sobie z dziwnymi problemami domenowymi Pow (). Jak 0 ^ 0 i -Niekończoność podniesiona do dowolnej potęgi.
InternalCall
zextern
modyfikatorem (ponieważ wydają się one być w konflikcie), zapoznaj się z pytaniem (i uzyskanymi odpowiedziami), które zamieściłem na ten temat.