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ę?

 407
Author: Gaurang Dave, 2012-01-15

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.

 828
Author: Hans Passant,
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.

 102
Author: Michael Graczyk,
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.

 63
Author: dasblinkenlight,
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