C#的Math.sqrt实施Math、sqrt

2023-09-03 02:31:10 作者:无路可退

我一直在使用System.Math颇多最近的一天,我在想,微软如何将已经实现在库中的sqrt方法。所以,我拧开我的最佳搭档反射器,并试图拆卸库的方法,但它表明:

[MethodImpl(MethodImplOptions.InternalCall),ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 公共静态外部双SQRT(双D);

这一天的第一次,我意识到我的孩子怎么养都在框架吃。

笑话之余,但我想知道什么样的算法MS的将用于实现该方法或你会怎么写自己的实现的Math.sqrt在C#中,如果你没有库支持等字样。

干杯

解决方案

任何你发现有MethodImplOptions.InternalCall属性的方法回来反射或参考源实际上是用C ++实现的CLR内。您可以从SSCLI20分布得到源$ C ​​$ C这些。相关文件是CLR / src目录/ VM / ecall.cpp,它包含了函数指针的方法名的表,使用的JIT编译器直接嵌入呼叫地址到生成的机器code。相关的表款是

  FCIntrinsic(产地来源证,COMDouble :: COS,CORINFO_INTRINSIC_Cos)
FCIntrinsic(的Sqrt,COMDouble ::的Sqrt,CORINFO_INTRINSIC_Sqrt)
FCIntrinsic(圆,COMDouble ::回合,CORINFO_INTRINSIC_Round)
...
 

这需要你CLR / src目录/ classlibnative /漂浮/ comfloat.cpp

  FCIMPL1_V(双,COMDouble ::的Sqrt,双D)
    WRAPPER_CONTRACT;
    STATIC_CONTRACT_SO_TOLERANT;

    返程(双)的sqrt(D);
FCIMPLEND
 
C 中Math.Sqrt 精度丢失怎样最小

这只是调用CRT函数。但是,这不是在x86抖动会发生什么,请注意内在的表声明。你不会发现在SSLI20版的抖动,这是一个简单的支配受到专利。在运费一人但不把它变成一种内在的:

 双D = 2.0;
        Console.WriteLine(的Math.sqrt(d)条);
 

转化为

  00000008 FLD DWORD PTR DS:[00721​​56Ch]
0000000e FSQRT
..等等
 

在换句话说,的Math.sqrt()转换为一个浮点机器code指令。检查this回答的详细信息,该如何击败本土code得心应手。

I've been using System.Math quite a lot lately and the other day I was wondering, how Microsoft would have implemented the Sqrt method in the library. So I popped open my best mate Reflector and tried to Disassemble the method in the library, but it showed:

[MethodImpl(MethodImplOptions.InternalCall),ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern double Sqrt(double d);

That day for the first time ever, I realized how dependent my kids are on the framework, to eat.

Jokes apart, but i was wondering what sort of algorithm MS would have used to implement this method or in other words how would you write your own implementation of Math.Sqrt in C# if you had no library support.

Cheers

解决方案

Any of the methods you find back with Reflector or the Reference Source that have the MethodImplOptions.InternalCall attribute are actually implemented in C++ inside the CLR. You can get the source code for these from the SSCLI20 distribution. The relevant file is clr/src/vm/ecall.cpp, it contains a table of method names with function pointers, used by the JIT compiler to directly embed the call address into the generated machine code. The relevant table section is

FCIntrinsic("Cos", COMDouble::Cos, CORINFO_INTRINSIC_Cos)
FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt)
FCIntrinsic("Round", COMDouble::Round, CORINFO_INTRINSIC_Round)
...

Which takes you to clr/src/classlibnative/float/comfloat.cpp

FCIMPL1_V(double, COMDouble::Sqrt, double d)
    WRAPPER_CONTRACT;
    STATIC_CONTRACT_SO_TOLERANT;

    return (double) sqrt(d);
FCIMPLEND

It just calls the CRT function. But that's not what happens in the x86 jitter, note the 'intrinsic' in the table declaration. You won't find that in the SSLI20 version of the jitter, it is a simple one unencumbered by patents. The shipping one however does turn it into an intrinsic:

        double d = 2.0;
        Console.WriteLine(Math.Sqrt(d));

translates to

00000008  fld         dword ptr ds:[0072156Ch] 
0000000e  fsqrt 
..etc

In other words, Math.Sqrt() translates to a single floating point machine code instruction. Check this answer for details on how that beats native code handily.