Alex Zywicki
Alex Zywicki

Reputation: 2313

Taylor Series based Sin() implementation using templates C++

I am working on an implementation of the sin() function based on the taylor series using templates. My code so far goes as follows:

template<unsigned I>
struct factorial{
    enum{  
    value = I * factorial<I -1>::value
    };
};
template<>
struct factorial<0>
{
    enum{ value = 1};
};
template<unsigned pow>
inline double power(double const& value){
    return value * power<pow-1>(value);
}
template<>
inline double power<1>(double const& value){
    return value;
}
template <unsigned term>
inline double taylor_sine_term(double const& x) {
    return (power<term>(-1) / factorial<(2*term)+1>::value) * power<(2*term)+1>(x);
}

The issue I am having is creating the function to use the taylor_sine_term function to expand the series for N number of terms.The function would be functionally equivalent to the following.

template<unsigned terms>
inline double taylor_sine(double const& x){
    return taylor_sine_term<1>(x)+taylor_sine_term<2>(x) + ... + taylor_sine_term<terms>(x);
}

Basically I need to figure out a way to generate a sequence of integer constants that can be used as the term number template parameter in the taylor_sine_term function for N number of terms and sum them all together. The result will expand into the full taylor series for N number of terms. The problem is I don't know where to start.

Any help is appreciated, Thanks.

Upvotes: 0

Views: 340

Answers (2)

Barry
Barry

Reputation: 303157

Same way you wrote the other ones: a recursive case and a base case:

template<unsigned terms>
inline double taylor_sine(double const& x) {
    return taylor_sine_term<terms>(x) + // current term
           taylor_sine<terms-1>(x);     // rest of terms
}

template <>
inline double taylor_sine<0>(const double& x) {
    return taylor_sine_term<0>(x);
}

Alternatively, you could use the index sequence trick to get all of them:

template <unsigned terms>
inline double taylor_sine(double const& x) {
    return taylor_sine(x, std::make_index_sequence<terms+1>{});
}

template <unsigned terms, size_t... Is>
inline double taylor_sine(const double& x, std::index_sequence<Is...> ) {
    double res = 0.0;
    for (double t : {taylor_sine_term<Is>(x)...}) {
        res += t;
    }
    return res;

    /* or in C++17
    return (taylor_sine_term<Is>(x) + ...);
    */
}

Note that you should change your base case on power to be power<0>.

Upvotes: 1

JSF
JSF

Reputation: 5321

It sounds like you want a recursively defined template

template<unsigned terms>
inline double taylor_sine(double const& x){
    return taylor_sine<terms-1>(x)+taylor_sine_term<terms>(x);
}

Then you would want to specialize for either 0 or 1 to terminate. But I think you can't specialize the function template, so you would need to bury that all in a functor template, which you can specialize.

Upvotes: 0

Related Questions