2011-02-08 86 views
10

最近我一直在使用System.Math,並且有一天我想知道Microsoft如何在庫中實現Sqrt方法。所以我擰開我的最佳搭檔反射器,並試圖拆卸庫的方法,但它表明:c#Math.Sqrt實現

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

當天的第一次,我意識到我的孩子怎麼養都是在框架上,吃。

笑話分開,但我想知道什麼樣的算法MS將用於實現此方法或換句話說,如果您沒有庫支持,如何在C#中編寫自己的Math.Sqrt實現。

乾杯

+6

出於興趣,我們最好的伴侶將在3月份時花費35美元...... – StuartLC 2011-02-08 10:30:29

回答

17

您使用Reflector或具有MethodImplOptions.InternalCall屬性的參考源找到的任何方法實際上都是在CLR內的C++中實現的。您可以從SSCLI20發行版中獲得這些源代碼。相關文件是clr/src/vm/ecall.cpp,它包含一個帶有函數指針的方法名錶,由JIT編譯器用來直接將調用地址嵌入到生成的機器代碼中。相關的錶款是

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

帶您到CLR/src目錄/ classlibnative /漂浮/ comfloat.cpp

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

    return (double) sqrt(d); 
FCIMPLEND 

它只是調用CRT功能。但是,這不是x86抖動中發生的情況,請注意表格聲明中的「內部」。在SSLI20版本的抖動中,您不會發現這種情況,這是一個簡單的方法,不受專利權限制。航運一個然而並把它變成一個固有:

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

轉化爲

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

換句話說,Math.Sqrt()轉換爲單個浮點機器代碼指令。查詢this answer瞭解如何輕鬆擊敗本機代碼。

4

該函數將被翻譯成彙編指令。如x87的fsqrt指令。

你可以在軟件中實現浮點數,但這很可能會慢得多。我認爲Sqrt是一種迭代算法的典型實現。

2

Google.com會給你比StackOverflow.com

看一看這個頁答案: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots 一種算法可以在標題下找到「二進制數字系統(基2)」在上面維基頁面。

但是,軟件實現將不會有效。現代CPU具有用於FPU數學函數的硬件實現。你只需要調用(彙編或機器語言)

+0

即使存儲在硬件中並稱爲微型程序,它仍然是軟件。 – 2011-02-08 10:39:30

1
public double Sqrt(int number) 
{ 
    double x = number/2; 

    for (int i = 0; i < 100; i++) x = (x + number/x)/2d; 

    return x; 
} 

非常粗略的方法處理器的正確說明,但如果我用的更精緻,如日誌的方法,你可以問:「我怎麼能實現日誌方法?「

+0

我不確定是否會得到最低有效位(s)正確。 – CodesInChaos 2011-02-08 10:38:25

+0

嗯,當然。這就是爲什麼我說這是非常「粗糙」的,當然,你可以迭代更多的次數來達到足夠的誤差,但是這會使算法變得不可讀。 `2d`爲`2`爲`double`。 – 2011-02-08 10:41:29