如何在.NET Framework中实现Math.Pow()?(How is Math.Pow() implemented in .NET Framework?)

编程入门 行业动态 更新时间:2024-10-27 23:18:26
如何在.NET Framework中实现Math.Pow()?(How is Math.Pow() implemented in .NET Framework?)

我正在寻找一个有效的方法来计算一个b (说a = 2和b = 50)。 要开始,我决定看看Math.Pow()函数的实现。 但是在.NET Reflector中 ,我发现的只有这一点:

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

当我调用Math.Pow()函数时,我可以看到内部的一些资源是什么?

I was looking for an efficient approach for calculating ab (say a = 2 and b = 50). To start things up, I decided to take a look at the implementation of Math.Pow() function. But in .NET Reflector, all I found was this:

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

What are some of the resources wherein I can see as what's going on inside when I call Math.Pow() function?

最满意答案

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()墙上,微软从Intel购买了这个代码。 做得比英特尔工程师更好的工作是不太可能的。 虽然我的高中书籍的身份是我尝试时的两倍:

public static double FasterPow(double x, double y) { return Math.Exp(y * Math.Log(x)); }

但不是一个真正的替代品,因为它累积了3个浮点运算的错误,并不处理Pow()具有的奇怪的域问题。 像0 ^ 0和-Infinity提升到任何权力。

MethodImplOptions.InternalCall

That means that the method is actually implemented in the CLR, written in C++. The just-in-time compiler consults a table with internally implemented methods and compiles the call to the C++ function directly.

Having a look at the code requires the source code for the CLR. You can get that from the SSCLI20 distribution. It was written around the .NET 2.0 time frame, I've found the low-level implementations, like Math.Pow() to be still largely accurate for later versions of the CLR.

The lookup table is located in clr/src/vm/ecall.cpp. The section that's relevant to Math.Pow() looks like this:

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()

Searching for "COMDouble" takes you to clr/src/classlibnative/float/comfloat.cpp. I'll spare you the code, just have a look for yourself. It basically checks for corner cases, then calls the CRT's version of pow().

The only other implementation detail that's interesting is the FCIntrinsic macro in the table. That's a hint that the jitter may implement the function as an intrinsic. In other words, substitute the function call with a floating point machine code instruction. Which is not the case for Pow(), there is no FPU instruction for it. But certainly for the other simple operations. Notable is that this can make floating point math in C# substantially faster than the same code in C++, check this answer for the reason why.

By the way, the source code for the CRT is also available if you have the full version of Visual Studio vc/crt/src directory. You'll hit the wall on pow() though, Microsoft purchased that code from Intel. Doing a better job than the Intel engineers is unlikely. Although my high-school book's identity was twice as fast when I tried it:

public static double FasterPow(double x, double y) { return Math.Exp(y * Math.Log(x)); }

But not a true substitute because it accumulates error from 3 floating point operations and doesn't deal with the weirdo domain problems that Pow() has. Like 0^0 and -Infinity raised to any power.

更多推荐

本文发布于:2023-07-14 23:46:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1108381.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:如何在   NET   Framework   implemented   Pow

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!