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

我正在寻找一种计算ab的有效方法(比如a = 2b = 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#代码和求幂通过平方算法。

链接地址: http://www.djcxy.com/p/14421.html

上一篇: How is Math.Pow() implemented in .NET Framework?

下一篇: Why do I need an IoC container as opposed to straightforward DI code?