是否可以計算一個整數的平方根與以下簽名元函數:平方根元函數?
template<unsigned int N> inline double sqrt();
(或者使用constexpr關鍵字,我不知道什麼是最好的)。 因此,sqrt<2>()
將在編譯時被替換爲1.414...
。
什麼是最好的實現這樣的功能?
是否可以計算一個整數的平方根與以下簽名元函數:平方根元函數?
template<unsigned int N> inline double sqrt();
(或者使用constexpr關鍵字,我不知道什麼是最好的)。 因此,sqrt<2>()
將在編譯時被替換爲1.414...
。
什麼是最好的實現這樣的功能?
這可能不是你在尋找什麼,但我想確保你意識到,通常在編譯時,編譯器通常通過優化來計算結果。例如,如果你有這樣的代碼:
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); }
大多數編譯器可能會在編譯時計算這個值,但這不是保證。 sqrt函數不返回'constexpr'值;該函數的輸出不能用作其他元函數的輸入。這不是一個真正的元函數,也不回答這個問題。 – aboveyou00
我看到的問題是,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。數學檢出:
你知道計算機不使用10的冪來存儲浮點值,對吧?此外,你已經有了指數和尾數交換的概念。 –
修正:)我知道十件事的力量,但由於我正在用小數,所以不會受到傷害。還補充說指數的選擇是任意的。 – Ghost2
但是如果你使用兩個冪,你可以使用'ldexp'來組合指數和尾數,而不需要任何乘法或除法。 –
徵包含此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 };
};
不能滿足這個要求。正是我需要的。 – romeric
我用Google搜索「模板元編程開方」和發現這個http://www.informit.com/articles/article.aspx?p=30667&seqNum=3 –
我已經看到,但它只是一個整數的sqrt的組成部分。我想在編譯時得到浮點結果。 – Vincent
因爲'sqrt'是一個標準函數,所以我會使用'sqrtt'來代替。 –