MethodImplOptions.InternalCall
Bu, yöntemin aslında C ++ ile yazılmış CLR'de uygulandığı anlamına gelir. Tam zamanında derleyici, dahili olarak uygulanan yöntemlerle bir tabloya danışır ve C ++ işlevine yapılan çağrıyı doğrudan derler.
Koda bir göz atmak CLR için kaynak kodunu gerektirir. Bunu SSCLI20 dağıtımından alabilirsiniz . .NET 2.0 zaman dilimi etrafında yazılmıştır, düşük seviyeli uygulamaları buldum Math.Pow()
, CLR'nin sonraki sürümleri için hala büyük ölçüde doğru olmak istiyorum .
Arama tablosu clr / src / vm / ecall.cpp dizininde bulunur. Alakalı bölüm şu Math.Pow()
şekildedir:
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" araması sizi clr / src / classlibnative / float / comfloat.cpp adresine götürür. Sana kodu yedekleyeceğim, sadece kendine bir bak. Temel olarak köşe durumlarını kontrol eder, ardından CRT'nin sürümünü çağırır pow()
.
İlginç olan diğer tek uygulama detayı tablodaki FCIntrinsic makrosudur. Bu, titreşimin işlevi içsel olarak uygulayabileceğine dair bir ipucu. Başka bir deyişle, işlev çağrısını bir kayan noktalı makine kodu komutuyla değiştirin. Bu durum böyle değil Pow()
, bunun için FPU talimatı yok. Ama kesinlikle diğer basit operasyonlar için. Dikkat çeken, bu C # 'daki kayan nokta matematiğini C ++' daki aynı koddan önemli ölçüde daha hızlı hale getirebilir, bu nedenle bu cevabı kontrol edin .
Bu arada, Visual Studio vc / crt / src dizininin tam sürümüne sahipseniz CRT için kaynak kodu da kullanılabilir. pow()
Yine de duvara çarpacaksınız , Microsoft bu kodu Intel'den satın aldı. Intel mühendislerinden daha iyi bir iş yapmak pek olası değildir. Lise kitabımın kimliği denediğimde iki kat daha hızlı olmasına rağmen:
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
Ancak gerçek bir yedek değildir, çünkü 3 kayan nokta işleminden hata biriktirir ve Pow () 'in sahip olduğu tuhaf etki alanı sorunlarıyla ilgilenmez. 0 ^ 0 ve -Infinity gibi herhangi bir güce yükseltildi.
InternalCall
birextern
değiştiriciyle karıştırıyorsanız ( çelişkili göründükleri gibi ), lütfen bu aynı şey hakkında gönderdiğim soruya (ve sonuçta ortaya çıkan cevaplara) bakın .