2015-12-11 11 views
5

Sto provando a creare una semplice funzione sine utilizzando l'espansione di taylor series che può essere valutata in fase di compilazione utilizzando C++ 14 constexpr. Il mio codice è in fase di compilazione, ma il compilatore non genera una costante.Espansione serie Taylor come constexpr

sine è definito come segue:

template <int P, typename T = double> constexpr T sine(T x) { 
    T result = x; 

    for (int i = 1; i < P; ++i) 
     result += power<T>(-1, i) * power<T>(x, 1 + 2 * i)/factorial<T>(1 + 2 * i); 

    return result; 
} 

posso fornire il codice per power e factorial se necessario. Sono banali e anche constexpr.

Sto chiamando da sine all'interno di un ciclo come questo:

template <int N> void test(double *out) { 
    for (int i = 0; i < N; ++i) { 
     out[i] = sine<20, double>(i * M_PI/N); 
    } 
} 

mi aspettavo che il compilatore può generare una serie di risultati per sine e metterli in out senza in realtà aver bisogno di calcolare la serie di Taylor . Invece il codice generato esegue sine come se fosse una qualsiasi altra funzione non constexpr.

Il mio compilatore è clang da Xcode 7.2 che compila con -O3.

risposta

6

mi aspettavo che il compilatore in grado di generare una serie di risultati per seno e metterli in fuori senza in realtà aver bisogno di calcolare la serie Taylor. Invece il codice generato viene eseguito come se fosse qualsiasi altra funzione non-constexpr.

Per una funzione constexpr da valutare in fase di compilazione si applicano le seguenti:

  • Tutti i suoi argomenti di input deve essere espressioni costanti.
  • Il risultato deve essere utilizzato in un'espressione costante.

L'assegnazione nel ciclo test non è un'espressione costante. Di conseguenza, non è possibile valutare sine in fase di compilazione.

Ciò che si desidera veramente è inizializzare staticamente gli elementi di un array utilizzando sine(). Usando un po 'di apparato std::array e aiutante questo è possibile farlo come illustrato di seguito:

#define r 0.01745329251 

constexpr double factorial(int n) { 
    double res = 1.0; 

    for(int i(2); i <= n; ++i) res *= i; 

    return res; 
} 

template<typename T> 
constexpr T power(T &&base, int const n) { 

    if(!n) return 0.0; 

    T res = base; 

    for(int i(1); i < n; ++i) res *= base; 

    return res; 
} 

template <typename T, int N = 5> 
constexpr T sine(T &&x) { 
    T res = x * r; 

    for (int i(3), sgn(-1); i <= N; i += 2, sgn = -sgn) { 
    res += power(x * r, i)/factorial(i); 
    } 

    return res; 
} 

template <class T, std::size_t N, std::size_t... Is> 
constexpr std::array<T, N> sine_array_impl(std::index_sequence<Is...>) { 
    return {{sine(T{Is})...}}; 
} 

template <class T, std::size_t N> 
constexpr std::array<T, N> sine_array() { 
    return sine_array_impl<T, N>(std::make_index_sequence<N>{}); 
} 

Live Demo

+0

non è il problema che la _argument_ a 'sine',' i * M_PI/N', isn è un constexpr? – Eric

+0

@Eric "Tutti i suoi argomenti di input devono essere espressioni costanti." non è abbastanza chiaro? – 101010

+0

Mi riferivo a _ "L'assegnazione nel ciclo for del test non è un'espressione costante" _. L'incarico è di per sé un problema qui? – Eric