Подтвердить что ты не робот

В С++ 11 sqrt определяется как constexpr?

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

Ответ 3

Ниже представлена ​​реализация корневого корня 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);
}

Ниже представлена ​​более удобная версия (для целочисленных констант), которая требует С++ 14, она похожа на ту, что представлена ​​в сообщении Baptiste Wicht в блоге. С++ 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);
}

Ответ 4

Вот быстрая и эффективная реализация 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();
}

Ответ 5

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

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

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

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