Use integer template argument to create compiletime double

Viewed 361

Is it possible to create a double which holds the value of 1*10^x where x is based on a integer template parameter. So something like:

template < int exp >
struct DoubleValue
{
    static constexpr double value = ????;
}

double d = DoubleValue<20>::value; // = 1e20
double d = DoubleValue<-20>::value; // = 1e-20

As it can be created with litterals, it seems that something like this should be possible.

I would like the value to be evaluated at compile time (so std::pow will not work as far as I know). Also, if possible, I would like to be able to avoid actual iterative computations ((maybe unfounded) fear for precision problems). I would also like to be able to use larger values as exponent, like for example 200, which makes it impossible to store the value in a standerd integer type.

3 Answers

Assuming that your compiler supports C++14 or higher (which should be a valid assumption in the year 2019) this is very simple using a constexpr function:

constexpr double myPow(double x, int exp)
{
    double pow = 1.0;
    for (int i = 0; i < exp; ++i)
        pow *= x;
    for (int i = 0; i > exp; --i)
        pow /= x;
    return pow;
}

template < int exp >
struct DoubleValue
{
    static constexpr double value = myPow(10.0, exp);
};

See here to verify that it works and that even without optimization the value is generated at compile time.

Depending on your use case you might not even need the DoubleValue struct but can directly use myPow().


Update

As pointed out by @Bob__ in the comments, there may be better algorithms regarding numerical precision than the one presented here. But since C++14 many basic language features can be used in the body of a constexpr function. So, as long as you don't need any external library for it, you are free to implement whatever algorithm fits your needs.

If you want it at compile time without std::pow, this should do it:

#include <iostream>

template <int e>
struct DoubleValue {
    static constexpr double value = 10.0 * DoubleValue<e - 1>::value;
};
template <>
struct DoubleValue<0> {
    static constexpr double value = 1.0;
};
int main() {
    std::cout << DoubleValue<20>::value << '\n'; //1e+20
}

C++ Fiddle

Since you need the value to available in compile time, pretty much the only way to solve it, that came to my mind is recursive templates. However, the fact, that you need for said template to do different things, based on the signedness of the passed value, complicates things. First thing that would come to mind, would be to write such a recursive template:

template <int exp>
struct DoubleValue
    {
    static constexpr double value = (exp < 0
                                     ? DoubleValue<exp+1>::value / 10
                                     : 10 * DoubleValue<exp-1>::value);
    };

// Default case
template <>
struct DoubleValue<0>
    {
    static constexpr double value = 1;
    };

However, such solution wouldn't work, due to the fact, that both branches of the ternary expression, would need to be resolved, and that would, always, lead to the infinite recursion, since one of the branches wouldn't tend to 0. Then, SFINAE came to mind:

// Base case.
template <int exp, class Enable = void>
struct DoubleValue
    {
    };

// Case when exp is positive
template <int exp>
struct DoubleValue<exp, typename std::enable_if<(exp > 0)>::type>
    {
    static constexpr double value = 10 * DoubleValue<exp-1>::value;
    };

// Case when exp is negative
template <int exp>
struct DoubleValue<exp, typename std::enable_if<(exp < 0)>::type>
    {
    static constexpr double value = DoubleValue<exp+1>::value / 10;
    };

// Default case.
template <>
struct DoubleValue<0>
    {
    static constexpr double value = 1;
    };

Live Demo.

Related