Jak matematyka.Pow () in.NET ramy?
Szukałem skutecznego podejścia do obliczania a b (powiedzmy a = 2
i b = 50
). Na początek postanowiłem przyjrzeć się implementacji funkcji Math.Pow()
. Ale w . Net Reflector znalazłem tylko to:
[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
public static extern double Pow(double x, double y);
Jakie są niektóre zasoby, w których mogę zobaczyć, co dzieje się wewnątrz, gdy wywołuję Math.Pow()
funkcję?
3 answers
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 kompiluje wywołanie funkcji C++ bezpośrednio.
Przyjrzenie się kodowi wymaga kodu źródłowego CLR. Możesz to uzyskać z dystrybucji SSCLI20 . Został napisany wokół ram czasowych. NET 2.0, znalazłem implementacje niskiego poziomu, jak Math.Pow()
nadal w dużej mierze dokładne dla późniejszych wersji CLR.
Tabela wyszukiwania znajduje się w CLR/src/vm/ecall.cpp. Sekcja, która jest istotna dla Math.Pow()
wygląda tak:
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, sam zobacz. Zasadniczo sprawdza przypadki narożne, a następnie wywołuje wersję CRT pow()
.
Jedynym interesującym szczegółem implementacji jest makro FCIntrinsic w stół. To wskazówka, że jitter może zaimplementować funkcję jako wewnętrzną. Innymi słowy, zastąp wywołanie funkcji zmiennoprzecinkową instrukcją kodu maszynowego. Co nie dotyczy Pow()
, nie ma dla niego instrukcji FPU. Ale na pewno dla innych prostych operacji. Warto zauważyć, że może to sprawić, że matematyka zmiennoprzecinkowa w C# będzie znacznie szybsza niż ten sam kod w C++, sprawdź tę odpowiedź z tego powodu.
Przy okazji, kod źródłowy dla CRT jest również dostępny, jeśli posiadasz pełną wersję katalogu Visual Studio vc / crt / src. Jednak Microsoft kupił ten kod od Intela. Wykonanie lepszej pracy niż inżynierowie Intela jest mało prawdopodobne. Chociaż tożsamość mojej książki w liceum była dwa razy szybsza, kiedy ją wypróbowałam:
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
Ale nie jest to prawdziwy substytut, ponieważ gromadzi błąd z 3 operacji zmiennoprzecinkowych i nie radzi sobie z dziwnymi problemami domeny, które ma Pow (). Jak 0^0 i-Nieskończoność podniesiony do potęgi.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:58
Odpowiedź Hansa Passanta jest świetna, ale chciałbym dodać, że jeśli b
jest liczbą całkowitą, to a^b
można obliczyć bardzo efektywnie z rozkładem binarnym. Oto zmodyfikowana wersja Henry 'ego Warrena Hacker' s Delight :
public static int iexp(int a, uint b) {
int y = 1;
while(true) {
if ((b & 1) != 0) y = a*y;
b = b >> 1;
if (b == 0) return y;
a *= a;
}
}
Zauważa, że operacja ta jest optymalna (wykonuje minimalną liczbę operacji arytmetycznych lub logicznych) dla wszystkich b a^b dla każdego b innego niż obszerne wyszukiwanie. To trudny problem. Więc w zasadzie oznacza to, że rozkład binarny jest tak dobry, jak to tylko możliwe.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:18
If pow
to nie wygląda jak coś, czego można się spodziewać. Znalezienie wersji. NET nie byłoby zbyt pomocne, ponieważ problem, który rozwiązujesz (tj. ten z liczbami całkowitymi), to prostsze porządki wielkości i może być rozwiązany w kilku liniach kodu C# z wykładnikiem za pomocą algorytmu kwadratowego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-16 23:43:36