MethodImplOptions.InternalCall
Это означает, что метод фактически реализован в CLR, написанном на C ++. Компилятор Just-in-Time обращается к таблице с внутренне реализованными методами и напрямую компилирует вызов функции 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));
}
Но не является истинной заменой, потому что он накапливает ошибку от 3 операций с плавающей запятой и не решает проблемы домена, которые есть у Pow (). Как 0 ^ 0 и бесконечность, возведенная в любую степень.
InternalCall
сextern
модификатором (так как они кажутся противоречивыми), пожалуйста, посмотрите вопрос (и полученные ответы), который я разместил об этой самой вещи.