6

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.

Rubix Cube
  • 108
  • 7
  • 3
    maybe `std::pow(10, exp)`? – iBug Jan 15 '19 at 09:21
  • 1
    @iBug he needs something with compile time, so `std::pow` will not work since it is not `constexpr`. – Marek R Jan 15 '19 at 09:24
  • 3
    Possible duplicate of [c++ power of integer, template meta programming](https://stackoverflow.com/questions/16443682/c-power-of-integer-template-meta-programming) – Ken Y-N Jan 15 '19 at 09:26
  • *"I would like the value to be evaluated at compile time*" — What would be the use for this? To speed-up your runtime? – Holt Jan 15 '19 at 09:40
  • I added static constexpr, I was indeed sloppy :) – Rubix Cube Jan 15 '19 at 09:43
  • To give some background, I would like te create a way to parse input numbers like 100M, 100K, 0.1m where the characters represent metric prefixes (https://en.m.wikipedia.org/wiki/Metric_prefix). But it should also work with our internal types (which I can create with an exponent). So I would like to create a template-specialization for creating a double with such exponent. – Rubix Cube Jan 15 '19 at 09:47
  • 1
    @RubixCube are [user-defined literals](https://en.cppreference.com/w/cpp/language/user_literal) what you are looking for? (C++11) – user268396 Jan 15 '19 at 10:43
  • @RubixCube also: instead of evaluating the actual value, you could choose to store a different representation, namely base + exponent instead and have a way to get the actual value at run time. That gives you fully `constexpr` building blocks, deferring actual computations until runtime. – user268396 Jan 15 '19 at 10:47
  • @user268396 It is used for parsing input and convert it to different types, PODs as well as a type similar as you describe – Rubix Cube Jan 21 '19 at 10:17

3 Answers3

6

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.

sebrockm
  • 5,733
  • 2
  • 16
  • 39
  • Off topic: "_Assuming that your compiler supports C++14 or higher (which should be a valid assumption in the year 2019)_"; When writing new projects, sure. But, in the project, that I am working on, we still have pieces of code being compiled with VS2003.. Legacy projects FTW! – Algirdas Preidžius Jan 15 '19 at 11:01
  • 1
    Luckily, the project I wanted to use this in was just updated :). I chose this anwer as it is clearer in its intent compared to recursive template solutions. – Rubix Cube Jan 15 '19 at 11:19
  • 1
    Please note that the algorithm used here is more prone to numeric errors than other alternatives: https://wandbox.org/permlink/tiupixvpbtwo9Zwd – Bob__ Jan 15 '19 at 15:14
1

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

MrMaavin
  • 1,611
  • 2
  • 19
  • 30
Stack Danny
  • 7,754
  • 2
  • 26
  • 55
  • What about the case of `std::cout << DoubleValue<-10>::value << std::endl;`? – Algirdas Preidžius Jan 15 '19 at 10:25
  • @AlgirdasPreidžius It is not hard to upgrade the code to work with negative powers, the idea stays the same. – lisyarus Jan 15 '19 at 10:26
  • 1
    @lisyarus Idea, yes, but one can't just throw `if`, or ternary expression, in there, since the both branches would need to be resolved, which would lead to infinite recursion. One would need to do more, than what is shown here, to force the same template to work with both positive, and negative numbers. – Algirdas Preidžius Jan 15 '19 at 10:28
  • @AlgirdasPreidžius You are absolutely right, this needs some template machinery to work, albeit pretty standard one, but potentially not familiar to the OP. – lisyarus Jan 15 '19 at 10:35
0

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.

Algirdas Preidžius
  • 1,769
  • 3
  • 14
  • 17