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.
InternalCallzexternmodyfikatorem (ponieważ wydają się one być w konflikcie), zapoznaj się z pytaniem (i uzyskanymi odpowiedziami), które zamieściłem na ten temat.