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++ 中的相同代码快得多,请检查此答案以了解原因。
顺便说一句,如果您有完整版的 Visual Studio vc/crt/src 目录,也可以获得 CRT 的源代码。不过,您会碰壁pow()
,微软从英特尔购买了该代码。比英特尔工程师做得更好是不可能的。虽然我的高中书的身份在我尝试的时候快了一倍:
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
但不是真正的替代品,因为它会累积来自 3 个浮点运算的错误,并且不处理 Pow() 所具有的怪异域问题。就像 0^0 和 -Infinity 提升到任何幂一样。