В С++ 11 sqrt определяется как constexpr?
В С++ 11 есть std::sqrt
, определенный как constexpr
, то есть может ли он легально использоваться из других функций constexpr
или во временных контекстах компиляции, таких как размеры массива или аргументы шаблона? g++, похоже, позволяет это (используя -std=c++0x
), но я не уверен, что могу считать это авторитетным, учитывая, что поддержка С++ 0x/С++ 11 по-прежнему неполна. Тот факт, что я не могу найти что-либо в Интернете, не дает мне знать.
Кажется, что это должно быть что-то, что можно было легко найти с помощью Google, но я пробовал (уже 40 минут...) и ничего не нашел. Я мог бы найти несколько предложений по добавлению constexpr в различные части стандартной библиотеки (например, этот), но ничего о sqrt
или других математических функциях.
Ответы
Ответ 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
, скорее всего, устранит это расширение, чтобы оно соответствовало.