Math.Pow()如何在.NET Framework中实现?

我正在寻找一个有效的方法来计算b (比如a = 2和b = 50)。 为了开始,我决定看看Math.Pow()函数的实现。 但在.NETreflection器 ,我发现是这样的:

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

当我调用Math.Pow()函数时,我可以看到里面发生了什么的一些资源是什么?

MethodImplOptions.InternalCall

这意味着该方法实际上是在C ++中编写的CLR中实现的。 即时编译器通过内部实现的方法查询表格,并直接编译调用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() 

search“COMDouble”会带你到clr / src / classlibnative / float / comfloat.cpp。 我会让你的代码,只是看看你自己。 它基本上检查angular落案件,然后调用CRT的pow()版本。

唯一有趣的其他实现细节是表中的FCIntrinsicmacros。 这是一个暗示,抖动可能实现作为一个内在的function。 换句话说,将函数调用replace为浮点机器码指令。 Pow()不是这种情况,没有FPU指令。 但是其他的简单操作 值得注意的是,这可以使C#中的浮点math运算速度大大快于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提高到任何力量。

Hans Passant的答案很好,但是我想补充一点,如果b是一个整数,那么可以通过二元分解非常有效地计算a^b 。 这里是亨利·沃伦“ 黑客的喜悦”的修改版:

 public static int iexp(int a, uint b) { int y = 1; while(true) { if ((b & 1) != 0) y = a*y; b = b >> 1; if (b == 0) return y; a *= a; } } 

他指出,对于所有b <15,这个操作是最优的(算术或逻辑运算的最小次数)。对于find一个最佳的因子序列来计算任何其他b的其他因子的一般问题,还没有已知的解决scheme比广泛的search。 这是一个NP难题。 所以基本上这意味着二元分解就像它得到的那样好。

如果免费提供C版本的pow是任何迹象,它看起来不像你期望的任何东西。 find.NET版本没有多大的帮助,因为你正在解决的问题(即整数的问题)的大小是比较简单的,可以在几行C#代码中用幂乘通过平方algorithm 。