web-dev-qa-db-ja.com

C ++ 11では、sqrtはconstexprとして定義されていますか?

C++ 11ではstd::sqrtconstexprとして定義されています。つまり、他のconstexpr関数から、または配列サイズやテンプレート引数などのコンパイル時コンテキストで合法的に使用できますか? g ++は(-std=c++0xを使用して)それを許可しているようですが、c ++ 0x/c ++ 11のサポートがまだ不完全であることを考えると、それを信頼できるものと見なすことができるかどうかはわかりません。インターネットで何も見つからないようで、不安になります。

これはグーグルを使って簡単に見つけられるもののようですが、私は試しましたが(今は40分間...)、何も見つかりませんでした。 constexprを標準ライブラリのさまざまな部分(たとえば this one )に追加するためのいくつかの提案を見つけることができましたが、sqrtやその他の数学関数については何もありませんでした。

40
sepp2k

N3291のセクション26.8によると、std::sqrtconstexprとして定義されていません:C++ 11 FDIS(そして、その後、最終標準に追加されたとは思えません)。そのようなバージョンを書くこともできますが、標準ライブラリのバージョンはconstexprではありません。

25
Nicol Bolas

誰かがメタ整数平方根関数に興味がある場合に備えて、これは私が以前に書いたものです:

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

これは、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();
}
16
Alex Shtof

以下は、二分探索を使用する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);
}
13
Linoliumz

C++ 11に最も近いドラフト標準を見ると N3337sqrtがマークされていないことがわかりますconstexpr、セクション26.8c.mathから:

これらのヘッダーの内容は、それぞれ標準Cライブラリヘッダーと同じですが、次の点が異なります。

sqrtへのconstexprの追加を含む変更はありません。

質問からわかるように gccは非定数式関数の組み込みを定数式と見なしていますgccは多くの数学関数をconstexprとしてマークします拡張子として。この拡張機能は 非準拠拡張機能 です。gccがこれを実装したときのリンクされた質問への回答で、準拠拡張機能のように見えましたが、これが変更され、gccは、この拡張機能が準拠するように修正する可能性があります。

9
Shafik Yaghmour