我一直在寻找一种计算ab的有效方法(比如 a = 2
和 b = 50
) . 为了开始,我决定看一下 Math.Pow()
函数的实现 . 但在.NET Reflector中,我发现的只有:
[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
public static extern double Pow(double x, double y);
当我调用 Math.Pow()
函数时,我可以看到内部发生了什么的一些资源?
3 回答
这意味着该方法实际上是在CLR中实现的,用C语言编写 . 即时编译器使用内部实现的方法查询表,并直接编译对C函数的调用 .
查看代码需要CLR的源代码 . 你可以从SSCLI20 distribution获得 . 它是围绕.NET 2.0时间框架编写的,我发现低级实现(如
Math.Pow()
)对于CLR的更高版本仍然基本准确 .查找表位于clr / src / vm / ecall.cpp中 . 与
Math.Pow()
相关的部分如下所示:搜索"COMDouble"会将您带到clr / src / classlibnative / float / comfloat.cpp . 我是'll spare you the code, just have a look for yourself. It basically checks for corner cases, then calls the CRT'的
pow()
版本 .唯一的其他实现细节's interesting is the FCIntrinsic macro in the table. That'暗示抖动可以将函数实现为内在函数 . 换句话说,用浮点机器代码指令替换函数调用 .
Pow()
不是这种情况,没有FPU指令 . 但肯定是其他简单的操作 . 值得注意的是,这可以使C#中的浮点数学运算速度明显快于C中的相同代码,因此检查this answer .顺便说一句,如果你有完整版本的Visual Studio vc / crt / src目录,也可以使用CRT的源代码 . 尽管如此,微软还是从英特尔那里购买了这些代码 . 不太可能比英特尔工程师做得更好 . 虽然我的高中书的身份是我尝试时的两倍:
但不是真正的替代品,因为它累积了来自3个浮点运算的错误,并且没有处理Pow()所具有的怪异域问题 . 像0 ^ 0和-Infinity提升到任何功率 .
Hans Passant's answer很棒,但我想补充一点,如果
b
是一个整数,那么a^b
可以通过二进制分解非常有效地计算 . 在这里's a modified version from Henry Warren' s Hacker's Delight:他指出,对于所有b <15,这个操作是最优的(算术或逻辑运算的最小数量) . 对于除了一个b之外的任何b,找到计算
a^b
的最佳因子序列的一般问题也没有已知的解决方案 . 广泛的搜索 . 这是NP难问题 . 所以基本上这意味着二进制分解和它一样好 .如果freely available C version of pow是任何指示,它看起来不像你期望的任何东西 . 找到.NET版本对你没有太大帮助,因为你正在解决的问题(即整数问题)是更简单的数量级,并且可以用几行C#代码with the exponentiation by squaring algorithm来解决 .