2011-12-24 107 views
32

在C++ 11 std::sqrt定義爲constexpr,即可以在法律上從其他constexpr功能或在編譯時環境狀陣列尺寸或模板參數被使用? G ++似乎它(使用-std=c++0x)允許,但我不知道我可以把它看作權威考慮到的C++ 0x/C++ 11的支持仍然是不完整的。事實上,我似乎無法在互聯網上找到任何東西,這讓我無法確定。在C++ 11中sqrt被定義爲constexpr?

看起來這應該是一個可以很容易地找到使用谷歌,但我試過(40分鐘吧......),但沒有找到任何東西。我能找到添加constexpr的標準庫的各個部分(例如像this one)的一些提案,但沒有約sqrt或其他數學函數。

回答

21

std::sqrt未被定義爲constexpr,根據N3291的第26.8節:C++ 11 FDIS(我懷疑他們在此之後將它添加到最終標準中)。有人可能會寫這樣的版本,但標準庫版本不是constexpr

+2

這是否明確規定? 26。8 C庫沒有提及constexpr。如果一個實現提供了constexpr函數實現以及那些沒有實現的實現,它肯定仍然是一致的。 – user2023370 2012-05-16 22:44:26

+6

@ user643722:標準庫實現*可以*定義一個'constexpr'版本。但它不是必需的,因此你不能真正依靠它。 – 2012-05-16 23:35:55

22

萬一有人有興趣元整數平方根函數,這裏是一個我而前寫道:

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

恩,這似乎有線性複雜性,即Theta(價值),而不是對數,這是很容易實現的,例如。在@Linoliumz的回答中。 – einpoklum 2016-02-10 11:57:44

13

下面是使用二進制搜索一個constexpr平方根實現。它正常達到2^64 gcc和鐺,其它更簡單的版本常常失敗數> 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,它類似於在巴普蒂斯特Wicht的blog post呈現的一個。 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); 
} 
+0

爲什麼'MID'是宏? – dyp 2014-12-30 16:51:44

+0

因爲在C++ 11中,constexpr函數內部的靜態const變量是不允許的。 – Linoliumz 2014-12-30 18:17:18

+0

這是爲了表明,還是人們真的使用了需要超過200次遞歸才能編譯的東西? – Mikhail 2014-12-30 19:01:09

3

如果我們看一下最近的標準草案,以C++ 11 N3337我們可以看到,sqrt沒有標記constexpr,從部分26.8c.math

內容這些標題與標準C庫 標題相同,並分別與以下 更改:

沒有任何的變化包括增加constexprsqrt

從問題Is gcc considering builtins of non-constant expression functions to be constant expressions可以看出,gcc將許多數學函數標記爲constexpr作爲擴展。這個擴展是non-conforming extension,正如我在回答鏈接問題時注意到的那樣,當gcc實現它時,它看起來就像是一個符合的擴展,但是這個改變了,並且gcc很可能將此擴展修復爲符合。

9

這是一個快速且高效的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(); 
}