c# - это - Как реализован Math.Pow() в.NET Framework?




подключить math c# (2)

Я искал эффективный подход для вычисления b (скажем, a = 2 и b = 50 ). Чтобы начать работу, я решил взглянуть на реализацию функции Math.Pow() . Но в .NET Reflector все, что я нашел, было следующим:

[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
public static extern double Pow(double x, double y);

Каковы некоторые из ресурсов, в которых я могу видеть, что происходит внутри, когда я вызываю Math.Pow() ?


MethodImplOptions.InternalCall

Это означает, что метод фактически реализован в CLR, написанном на C ++. Компилятор «точно в срок» обращается к таблице с внутренне реализованными методами и напрямую компилирует вызов функции C ++.

Для просмотра кода требуется исходный код для CLR. Вы можете получить это из дистрибутива SSCLI20 . Это было написано вокруг временного интервала .NET 2.0. Я обнаружил, что реализации низкого уровня, такие как Math.Pow() по-прежнему в значительной степени точны для более поздних версий CLR.

Таблица поиска находится в файле clr / src / vm / ecall.cpp. Раздел, относящийся к Math.Pow() выглядит следующим образом:

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()

Поиск «COMDouble» приведет вас к clr / src / classlibnative / float / comfloat.cpp. Я пощажу вам код, просто взгляните на себя. Он в основном проверяет угловые случаи, затем называет версию CRT pow() .

Единственная другая деталь реализации, которая интересна, - это макрос FCIntrinsic в таблице. Это намек на то, что джиттер может реализовать функцию как внутреннюю. Другими словами, замените вызов функции инструкцией машинного кода с плавающей запятой. Что не относится к Pow() , для него нет инструкции FPU. Но, конечно же, для других простых операций. Примечательно, что это может сделать математику с плавающей запятой в C # существенно быстрее, чем тот же код на C ++, проверьте этот ответ по этой причине.

Кстати, исходный код для CRT также доступен, если у вас есть полная версия каталога Visual Studio vc / crt / src. Вы попадете в стену на pow() хотя Microsoft купила этот код у Intel. Лучше работать, чем инженеры Intel, маловероятно. Хотя моя личность школьной книги была в два раза быстрее, когда я это пробовал:

public static double FasterPow(double x, double y) {
    return Math.Exp(y * Math.Log(x));
}

Но не настоящая замена, потому что она накапливает ошибку из трех операций с плавающей запятой и не имеет дело с проблемами домена Weirdo, которые имеет Pow (). Как 0 ^ 0 и -Infinity подняты до любой степени.


Если свободно доступна версия C версии pow , это не похоже на то, что вы ожидаете. Было бы не очень полезно найти версию .NET, потому что проблема, которую вы решаете (т. Е. С целыми числами), упрощает порядки величин и может быть решена в нескольких строках кода C # с экспоненциацией алгоритмом возведения в квадрат .







pow