48

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

似乎这应该是使用 Google 可以轻松找到的东西,但我已经尝试过(现在已经 40 分钟......)并且找不到任何东西。我可以找到几个将 constexpr 添加到标准库的各个部分的建议(例如这个),但没有关于sqrt其他数学函数的内容。

4

6 回答 6

30

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

于 2011-12-24T02:23:12.337 回答
24

以防万一有人对元整数平方根函数感兴趣,这是我之前写的一个:

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);
}
于 2011-12-24T14:11:22.000 回答
21

这是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();
}
于 2015-12-07T12:54:27.250 回答
13

下面是一个使用二分搜索的 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);
}
于 2014-12-30T16:42:08.897 回答
9

如果我们查看与 C++11 N3337最接近的标准草案,我们可以看到sqrt未标记constexpr,来自26.8 c.math部分:

这些头文件的内容与标准 C 库头文件相同,并且分别具有以下更改:

没有任何更改包括将constexpr添加到sqrt.

我们可以从问题Is gcc Considering builtins of non-constant expression functions to be constant expressions 中可以看出,这将gcc许多数学函数标记为constexpr作为扩展。这个扩展是一个不符合标准的扩展,正如我在对链接问题的回答中指出的那样,当gcc实现它时,它看起来像是一个符合标准的扩展,但它发生了变化,并且gcc很可能修复这个扩展以符合标准。

于 2015-02-01T18:10:48.330 回答
9

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

于 2020-08-03T15:25:31.737 回答