MethodImplOptions.InternalCall
Это означает, что метод на самом деле реализуется в CLR, написанный на C++. Компилятор «точно в срок» обращается к таблице с внутренне реализованными методами и напрямую компилирует вызов функции C++.
Для просмотра кода необходим исходный код для CLR. Вы можете получить это от SSCLI20 distribution. Он был написан вокруг временного интервала .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/плавать/comfloat.cpp. Я пощажу вам код, просто взгляните на себя. Он в основном проверяет угловые случаи, затем называет версию CRT pow()
.
Единственная другая деталь реализации, которая интересна, это макрос FCIntrinsic в таблице. Это намек на то, что джиттер может реализовать функцию как внутреннюю. Другими словами, замените вызов функции инструкцией машинного кода с плавающей запятой. Что не относится к Pow()
, для него нет инструкции FPU. Но, конечно же, для других простых операций. Примечательно, что это может сделать математику с плавающей запятой в C# существенно быстрее, чем тот же код в C++, по этой причине проверьте this answer.
Кстати, исходный код для 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 и -Infinity подняты до любой степени.
Как и в случае с FYI, если вы запутались во всём 'InternalCall' с модификатором' extern' (поскольку они _seem_ будут конфликтующими), см. [Вопрос (и результирующие ответы)] (http: /stackoverflow.com/questions/1211462/c-sharp-internal-static-extern-with-internalcall-attribute-internal-or-externa), который я опубликовал об этом самом же. – CraigTP
Для операции '2^x', если' x' является целым числом, результатом является операция сдвига. Поэтому, возможно, вы могли бы построить результат, используя мантиссу «2» и показатель «x». – ja72
@SurajJain ваш комментарий на самом деле вопрос, который вам нужно отправить отдельно. – ja72