2012-09-02 94 views
6

是否可以計算一個整數的平方根與以下簽名元函數:平方根元函數?

template<unsigned int N> inline double sqrt(); 

(或者使用constexpr關鍵字,我不知道什麼是最好的)。 因此,sqrt<2>()將在編譯時被替換爲1.414...

什麼是最好的實現這樣的功能?

+0

我用Google搜索「模板元編程開方」和發現這個http://www.informit.com/articles/article.aspx?p=30667&seqNum=3 –

+0

我已經看到,但它只是一個整數的sqrt的組成部分。我想在編譯時得到浮點結果。 – Vincent

+0

因爲'sqrt'是一個標準函數,所以我會使用'sqrtt'來代替。 –

回答

8

這可能不是你在尋找什麼,但我想確保你意識到,通常在編譯時,編譯器通常通過優化來計算結果。例如,如果你有這樣的代碼:

void g() 
{ 
    f(sqrt(42)); 
} 

隨着G ++ 4.6.3與優化-O2,產生的彙編代碼:

9 0000 83EC1C    subl $28, %esp 
    11 0003 DD050000    fldl .LC0 
    12 0009 DD1C24    fstpl (%esp) 
    13 000c E8FCFFFF    call _Z1fd 
    14 0011 83C41C    addl $28, %esp 
    16 0014 C3     ret 
    73     .LC0: 
    74 0000 6412264A    .long 1244009060 
    75 0004 47EC1940    .long 1075440711 

sqrt函數實際上從來不叫,和值只是作爲程序的一部分存儲。

因此創建在技術上滿足您需求的功能,你只需將需要:

template<unsigned int N> inline double meta_sqrt() { return sqrt(N); } 
+1

大多數編譯器可能會在編譯時計算這個值,但這不是保證。 sqrt函數不返回'constexpr'值;該函數的輸出不能用作其他元函數的輸入。這不是一個真正的元函數,也不回答這個問題。 – aboveyou00

0

我看到的問題是,metaP有效地濫用枚舉變量。問題在於枚舉在內部被視爲整數,從而排除嘗試從中獲得浮點值的問題。但是,您可能可以創建自己的浮點格式來創建兩個結果,一個整數部分和一個指數。您仍然必須將其處理爲浮點數,如Out = Sqrt<42>::mantissa * pow(10,Sqrt<42>::exponent);。實際上,確定這些值是作爲練習給讀者的,但是您可能需要向上調整輸入(以10的偶數次冪),計算根,並存儲之前使用的-power/2。要計算sqrt < 42>,首先要將指數枚舉設置爲合適的冪,例如'-4'(越小,數字越多,但注意溢出)。您然後乘以'10 ^( - 2 *指數)'的輸入。在這種情況下,您得到42 * 10^8 = 4200000000.然後,您將該值的根獲得'64807'作爲最終值。在運行時,計算「val * 10^exponent」=「64807 * 10^-4」= 64807 * 0.0001 = 6.4807m並將其存儲爲浮點數。

額外的轉換工作有點挫敗了目的,但您可以通過將指數存儲爲10^k(即10^4)然後執行out=sqrt<x>::mantissa/sqrt<x>::exponent來減少它。

編輯我剛剛注意到,用尾數/指數方法,指數的選擇是任意的,只要它大於最終根的整數部分。它甚至可以是一個常數,這可以簡化元函數的設計。例如,在42的情況下,您可以選擇'指數'始終爲6000.然後將輸入乘以6000^2,乘以產品的整數根,然後在運行時將結果除以6000以得到根。它不是將輸出視爲* 10^b,而是使用關係sqr(x * b^2)= sqr(x)* b。數學檢出:

  • 42 * 6000 * 6000 = 15.12億
  • SQR(15.12億)= 38884
  • 六千分之三萬八千八百八十四= 6.4806(平方被41.999)
+2

你知道計算機不使用10的冪來存儲浮點值,對吧?此外,你已經有了指數和尾數交換的概念。 –

+0

修正:)我知道十件事的力量,但由於我正在用小數,所以不會受到傷害。還補充說指數的選擇是任意的。 – Ghost2

+2

但是如果你使用兩個冪,你可以使用'ldexp'來組合指數和尾數,而不需要任何乘法或除法。 –

4

徵包含此meta_sqrt它採用二進制搜索:

template<int Y, 
     int InfX = 0, 
     int SupX = ((Y==1) ? 1 : Y/2), 
     bool Done = ((SupX-InfX)<=1 ? true : ((SupX*SupX <= Y) && ((SupX+1)*(SupX+1) > Y))) > 
           // use ?: instead of || just to shut up a stupid gcc 4.3 warning 
class meta_sqrt 
{ 
    enum { 
    MidX = (InfX+SupX)/2, 
    TakeInf = MidX*MidX > Y ? 1 : 0, 
    NewInf = int(TakeInf) ? InfX : int(MidX), 
    NewSup = int(TakeInf) ? int(MidX) : SupX 
}; 
    public: 
    enum { ret = meta_sqrt<Y,NewInf,NewSup>::ret }; 
}; 

template<int Y, int InfX, int SupX> 
class meta_sqrt<Y, InfX, SupX, true> 
{ 
    public: enum { ret = (SupX*SupX <= Y) ? SupX : InfX }; 
}; 
+0

不能滿足這個要求。正是我需要的。 – romeric