В C ++ 11 определяется sqrt как constexpr? - PullRequest
38 голосов
/ 24 декабря 2011

В C ++ 11 std::sqrt определяется как constexpr, т. Е. Может ли он по закону использоваться из других constexpr функций или в контексте времени компиляции, таких как размеры массивов или аргументы шаблона? g ++, кажется, позволяет это (используя -std=c++0x), но я не уверен, что могу считать это авторитетным, учитывая, что поддержка c ++ 0x / c ++ 11 все еще не завершена. Тот факт, что я ничего не могу найти в Интернете, заставляет меня сомневаться.

Кажется, это должно быть что-то, что можно легко узнать с помощью Google, но я пытался (в течение 40 минут ...) и не мог ничего найти. Я мог бы найти несколько предложений по добавлению constexpr в различные части стандартной библиотеки (например, this ), но ничего о sqrt или других математических функциях.

Ответы [ 5 ]

24 голосов
/ 24 декабря 2011

std::sqrt не определено как constexpr, согласно разделу 26.8 N3291: FDIS C ++ 11 (и я сомневаюсь, что после этого они добавили его в окончательный стандарт).Можно было бы написать такую ​​версию, но стандартная версия библиотеки не constexpr.

23 голосов
/ 24 декабря 2011

На всякий случай, если кому-то интересна мета-целочисленная функция квадратного корня, вот что я написал некоторое время назад:

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);
}
14 голосов
/ 07 декабря 2015

Вот быстрая и эффективная реализация constexpr для double чисел с плавающей запятой.Вы также можете адаптировать его к 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();
}
13 голосов
/ 30 декабря 2014

Ниже приведена реализация квадратного корня constexpr, которая использует бинарный поиск. Он работает корректно до 2 ^ 64 с gcc и clang, другие более простые версии часто терпят неудачу для чисел> 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, она аналогична той, что представлена ​​в блоге Баптиста Вихта . 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);
}
8 голосов
/ 01 февраля 2015

Если мы посмотрим на ближайший проект стандарта C ++ 11 N3337 , то увидим, что sqrt не помечено constexpr из раздела 26.8 c.math :

Содержимое этих заголовков такое же, как заголовки библиотеки Standard C и, соответственно, со следующими изменениями:

Ни одно из измененийвключает добавление constexpr к sqrt.

Мы можем видеть из вопроса Рассматривает ли gcc встроенные функции неконстантных выражений как постоянные выражения , что gcc помечает многие математические функции как constexpr какрасширение.Это расширение является несоответствующим расширением , как я отмечаю в своем ответе на связанный вопрос, когда gcc реализовал это, похоже, что это будет соответствующее расширение, но это изменилось, и gcc, вероятно,исправьте это расширение, чтобы оно соответствовало требованиям.

...