在C ++ 11中,std::sqrt
定义为constexpr
,即它是否可以合法地从其他constexpr
函数或编译时上下文(如数组大小或模板参数)中使用? g ++似乎允许它(使用-std=c++0x
),但我不确定我是否可以将其视为权威,因为c ++ 0x / c ++ 11支持仍然不完整。事实上,我似乎无法在互联网上找到任何东西,这让我不确定。
看起来这应该是人们可以轻易找到使用谷歌的东西,但我已经尝试过(现在40分钟......)并且找不到任何东西。我可以找到几个建议,将constexpr添加到标准库的各个部分(例如this one),但没有关于sqrt
或其他数学函数的内容。
答案 0 :(得分:24)
std::sqrt
未被定义为constexpr
:C ++ 11 FDIS(我怀疑他们之后将其添加到最终标准中)。有人可能会编写这样的版本,但标准库版本不是constexpr
。
答案 1 :(得分:23)
以防任何人对元整数平方根函数感兴趣,这是我在前一段时间写的:
constexpr std::size_t isqrt_impl
(std::size_t sq, std::size_t dlt, std::size_t value){
return sq <= value ?
isqrt_impl(sq+dlt, dlt+2, value) : (dlt >> 1) - 1;
}
constexpr std::size_t isqrt(std::size_t value){
return isqrt_impl(1, 3, value);
}
答案 2 :(得分:14)
这是double
浮点数的快速有效的constexpr实现。如果需要,您也可以将其调整为float
:
#include <limits>
namespace Detail
{
double constexpr sqrtNewtonRaphson(double x, double curr, double prev)
{
return curr == prev
? curr
: sqrtNewtonRaphson(x, 0.5 * (curr + x / curr), curr);
}
}
/*
* Constexpr version of the square root
* Return value:
* - For a finite and non-negative value of "x", returns an approximation for the square root of "x"
* - Otherwise, returns NaN
*/
double constexpr sqrt(double x)
{
return x >= 0 && x < std::numeric_limits<double>::infinity()
? Detail::sqrtNewtonRaphson(x, x, 0)
: std::numeric_limits<double>::quiet_NaN();
}
答案 3 :(得分:13)
下面是一个使用二进制搜索的constexpr平方根实现。它使用gcc和clang可以正常工作到2 ^ 64,其他更简单的版本通常会因数字而失败&gt;因为编译器将递归深度限制为例如2 ^ 32 200。
// C++11 compile time square root using binary search
#define MID ((lo + hi + 1) / 2)
constexpr uint64_t sqrt_helper(uint64_t x, uint64_t lo, uint64_t hi)
{
return lo == hi ? lo : ((x / MID < MID)
? sqrt_helper(x, lo, MID - 1) : sqrt_helper(x, MID, hi));
}
constexpr uint64_t ct_sqrt(uint64_t x)
{
return sqrt_helper(x, 0, x / 2 + 1);
}
下面是一个更好的版本(对于整数常量)需要C ++ 14,它类似于Baptiste Wicht的blog post中提供的版本。允许C ++ 14 constexpr函数使用局部变量和if语句。
// C++14 compile time square root using binary search
template <typename T>
constexpr T sqrt_helper(T x, T lo, T hi)
{
if (lo == hi)
return lo;
const T mid = (lo + hi + 1) / 2;
if (x / mid < mid)
return sqrt_helper<T>(x, lo, mid - 1);
else
return sqrt_helper(x, mid, hi);
}
template <typename T>
constexpr T ct_sqrt(T x)
{
return sqrt_helper<T>(x, 0, x / 2 + 1);
}
答案 4 :(得分:7)
如果我们查看最接近C ++ 11的标准草案N3337,我们可以看到sqrt
未标记为 constexpr ,来自26.8
< EM> c.math :
这些标头的内容与标准C库相同 标题和分别具有以下内容 变化:
所有更改都不包括将 constexpr 添加到sqrt
。
我们可以从问题Is gcc considering builtins of non-constant expression functions to be constant expressions看出,gcc
将许多数学函数标记为 constexpr 作为扩展名。这个扩展名为non-conforming extension,正如我在gcc
实施此问题时对链接问题的回答中所述,它看起来像是一个符合标准的扩展名,但这已经改变,gcc
可能会修复这个扩展要符合要求。
答案 5 :(得分:3)
现在有一个提案P1383R0 More constexpr for <cmath>
and <complex>
(Edward J. Rosten, Oliver J. Rosten),不幸的是尚未纳入C ++ 20,从最新评论来看,也可能不在C ++ 23中。 C ++ 26?