C++ 平方根元函数?
是否可以使用具有以下签名的元函数计算整数的平方根:C++ 平方根元函数?,c++,templates,metaprogramming,sqrt,C++,Templates,Metaprogramming,Sqrt,是否可以使用具有以下签名的元函数计算整数的平方根: template<unsigned int N> inline double sqrt(); 模板内联双sqrt(); (或者使用constexpr关键字,我不知道什么是最好的)。 这样,编译时,sqrt()将被1.414…替换 对于这样一个函数,什么是最好的实现?我看到的问题是metaP有效地将枚举滥用到变量中。问题是枚举在内部被视为整数,这就排除了从中获取浮点值的可能性。但是,您可以创建自己的浮点格式,该格式可以创建两个结果
template<unsigned int N> inline double sqrt();
模板内联双sqrt();
(或者使用constexpr关键字,我不知道什么是最好的)。
这样,编译时,sqrt()
将被1.414…
替换
对于这样一个函数,什么是最好的实现?我看到的问题是metaP有效地将枚举滥用到变量中。问题是枚举在内部被视为整数,这就排除了从中获取浮点值的可能性。但是,您可以创建自己的浮点格式,该格式可以创建两个结果,一个整数部分和一个指数。您仍然需要将其处理为浮点,如
Out=Sqrt::尾数*pow(10,Sqrt::exponent)代码>。实际上,确定这些值是留给读者的一个练习,但是您可能需要向上扩展输入(以10的偶数幂次),计算根,并存储您之前使用的-power/2
要计算sqrt,首先将指数enum设置为合适的幂,例如“-4”(小数越小,小数越多,但要注意溢出)。然后将输入乘以“10^(-2*指数)”。在这种情况下,得到42*10^8=4200000000。然后取该值的根,将“64807”作为最终值。在运行时,计算“val*10^指数”=“64807*10^-4”=64807*0.0001=6.4807m并将其存储到浮点
额外的转换工作有点达不到目的,但是您可以通过将指数存储为10^k(即10^4),然后执行out=sqrt::尾数/sqrt::exponent
来减少它
编辑我刚刚注意到,对于尾数/指数方法,指数的选择是任意的,只要它大于最终根的整数部分。它甚至可以是一个常数,这简化了元函数的设计。例如,在42的情况下,您可以选择“指数”始终为6000。然后将输入乘以6000^2,取乘积的整数根,然后在运行时将结果除以6000,得到根。它使用关系sqr(x*b^2)=sqr(x)*b,而不是将输出视为a*10^b。数学证明:
- 42*6000*6000=1512000000
- sqr(1512000000)=38884
- 38884/6000=6.4806(平方为41.999)
这可能不是您想要的,但我想确保您意识到,通常通过优化,编译器将在编译时计算结果。例如,如果您有以下代码:
void g()
{
f(sqrt(42));
}
使用带有优化-O2的g++4.6.3,生成的汇编代码为:
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); }
template inline double meta_sqrt(){return sqrt(N);}
Eigen包含这个使用二进制搜索的meta\u 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 };
};
模板Y?1 : 0,
NewInf=int(TakeInf)?InfX:int(MidX),
NewSup=int(TakeInf)?int(MidX):SupX
};
公众:
枚举{ret=meta_sqrt::ret};
};
模板
类meta_sqrt
{
public:enum{ret=(SupX*SupX I谷歌搜索“模板元编程sqrt”我已经看到了这一点,但它只适用于整数的sqrt的整数部分。我希望在编译时得到浮点结果。因为sqrt
是一个标准函数,我会使用sqrtt
来代替。你能在编译时对浮点数做任何有意义的操作吗?包括平方根用牛顿求根法实现的函数。(查看自述文件示例)。你知道计算机不使用10的幂来存储浮点值,对吗?此外,你还交换了指数和尾数的概念。修复:)我知道十的幂,但因为我用的是小数,所以这没什么坏处。我还补充说,指数的选择是任意的。但是如果你使用二的幂,你可以使用ldexp
组合指数和尾数,而不需要任何乘法或除法。大多数编译器可能都会计算出这两个数t编译时,但这不是保证。sqrt函数不返回constepr
值;此函数的输出不能用作其他元函数的输入。这不是真正的元函数,也不能回答问题。