48

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

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

4

6 に答える 6

30

std::sqrtconstexprN3291のセクション26.8によると、はとして定義されていません:C ++ 11 FDIS(そして、その後、最終標準に追加されたとは思えません)。そのようなバージョンを書くこともできますが、標準ライブラリのバージョンはそうではありません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まで正しく動作しますが、コンパイラが再帰の深さをたとえば200に制限しているため、他の単純なバージョンは2^32を超える数値で失敗することがよくあります。

// 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を必要とするより良いバージョン(整数定数用)であり、BaptisteWichtのブログ投稿に示されているものと似ています。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に最も近いドラフト標準を見ると、セクションc.mathからconstexprsqrtとマークされていないことがわかります。26.8

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

変更には、constexprの追加は含まれていませんsqrt

質問からわかるように、gccは、非定数式関数の組み込みを定数式と見なしています。これは、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 に答える