在c++ 11中,sqrt定义为constexpr

In C++11 is sqrt defined as constexpr?

本文关键字:定义 constexpr sqrt c++      更新时间:2023-10-16

在c++ 11中std::sqrt被定义为constexpr,即它可以合法地从其他constexpr函数或在编译时上下文中使用,如数组大小或模板参数?g++似乎允许它(使用-std=c++0x),但我不确定我可以把它作为权威,因为c++0x/c++11的支持仍然不完整。我在网上似乎找不到任何东西,这一事实使我拿不准。

似乎这应该是一个可以很容易地找到用谷歌,但我已经尝试了(40分钟了…),没有找到任何东西。我可以找到几个将constexpr添加到标准库的各个部分的建议(例如这个),但没有关于sqrt或其他数学函数的建议。

std::sqrt没有定义为constexpr,根据N3291: c++ 11 FDIS的第26.8节(我怀疑他们在那之后将其添加到最终标准中)。可以编写这样一个版本,但是标准库版本不是constexpr

这是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();
}

如果有人对元整数平方根函数感兴趣,这里是我一年前写的一个:

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);
}

下面是一个使用二进制搜索的constexpr平方根实现。在gcc和clang中,它可以正确地工作到2^64,其他更简单的版本通常无法处理> 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的博客文章中给出的版本。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);
}

现在有一个提案P1383R0 <cmath><complex>的更多constexpr (Edward J. Rosten, Oliver J. Rosten),不幸的是,它没有进入c++ 20,从最新的评论来看,可能也不在c++ 23中。c++ 26吗?

如果我们看一下最接近c++ 11 N3337的标准草案,我们可以看到sqrt没有标记constexpr,从26.8 C .math:

这些头文件的内容与标准C库相同头和分别与以下内容变化:

没有变化包括添加constexprsqrt

我们可以从gcc是否将内置的非常量表达式函数视为常量表达式的问题中看到,gcc将许多数学函数标记为constexpr作为扩展。这个扩展是一个不符合要求的扩展,正如我在回答gcc实现这个链接的问题时注意到的,它看起来像它会是一个符合要求的扩展,但这改变了,gcc很可能会修复这个扩展是符合要求的。