Ответ 1
MethodImplOptions.InternalCall
Это означает, что метод фактически реализован в CLR, написанном на С++. Компилятор "точно в срок" обращается к таблице с внутренне реализованными методами и напрямую компилирует вызов функции С++.
Взглянув на код, требуется исходный код для 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. Но, конечно же, для других простых операций. Примечательно, что это может сделать математику с плавающей запятой в С# существенно быстрее, чем тот же код в С++, проверьте этот ответ по этой причине.
Кстати, исходный код для 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, поднятые до любой степени.