Math.Pow()如何在.NET Framework中实现?
我正在寻找一种计算ab的有效方法(比如a = 2
和b = 50
)。 为了开始,我决定看看Math.Pow()
函数的实现。 但在.NET Reflector中,我发现的只有这个:
[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()
搜索“COMDouble”会将您带到clr / src / classlibnative / float / comfloat.cpp。 我会让你知道代码,只需要看看你自己。 它基本上检查角落案件,然后调用CRT的pow()
版本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提高到任何力量。
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,还没有已知的解决方案寻找的因素的最优序列的一般问题,以计算a^b
为其他任何B-比广泛的搜索。 这是一个NP难题。 所以基本上这意味着二元分解就像它得到的那样好。
如果免费提供C版本的pow
可以表明任何迹象,它看起来不像你期望的任何东西。 这对你找到.NET版本没有太大的帮助,因为你正在解决的问题(即整数问题)的大小顺序更简单,并且可以用几行C#代码和求幂通过平方算法。
上一篇: How is Math.Pow() implemented in .NET Framework?
下一篇: Why do I need an IoC container as opposed to straightforward DI code?