std::ratio power of a std::ratio at compile-time? - c++

I have a challenging question from a mathematical, algorithmic and metaprogramming recursion point of view. Consider the following declaration:
template<class R1, class R2>
using ratio_power = /* to be defined */;
based on the example of the std::ratio operations like std::ratio_add. Given, two std::ratio R1 and R2 this operation should compute R1^R2 if and only if R1^R2 is a rational number. If it is irrational, then the implementation should fail, like when one try to multiply two very big ratios and the compiler say that there is an integer overflow.
Three questions:
Do you think this is possible without exploding the compilation
time?
What algorithm to use?
How to implement this operation?

You need two building blocks for this calculation:
the n-th power of an integer at compile-time
the n-th root of an integer at compile-time
Note: I use int as type for numerator and denominator to save some typing, I hope the main point comes across. I extract the following code from a working implementation but I cannot guarantee that I will not make a typo somewhere ;)
The first one is rather easy: You use x^(2n) = x^n * x^n or x^(2n+1) = x^n * x^n * x
That way, you instantiate the least templates, e.g. x^39 be calculated something like that:
x39 = x19 * x19 * x
x19 = x9 * x9 * x
x9 = x4 * x4 * x
x4 = x2 * x2
x2 = x1 * x1
x1 = x0 * x
x0 = 1
template <int Base, int Exponent>
struct static_pow
{
static const int temp = static_pow<Base, Exponent / 2>::value;
static const int value = temp * temp * (Exponent % 2 == 1 ? Base : 1);
};
template <int Base>
struct static_pow<Base, 0>
{
static const int value = 1;
};
The second one is a bit tricky and works with a bracketing algorithm:
Given x and N we want to find a number r so that r^N = x
set the interval [low, high] that contains the solution to [1, 1 + x / N]
calculate the midpoint mean = (low + high) / 2
determine, if mean^N >= x
if yes, set the interval to [low, mean]
if not, set the interval to [mean+1, high]
if the interval contains only one number, the calculation is finished
otherwise, iterate again
This algorithm gives the largest integer s that folfills s^N <= x
So check whether s^N == x. If yes, the N-th root of x is integral, otherwise not.
Now lets write that as compile-time program:
basic interface:
template <int x, int N>
struct static_root : static_root_helper<x, N, 1, 1 + x / N> { };
helper:
template <int x, int N, int low, int high>
struct static_root_helper
{
static const int mean = (low + high) / 2;
static const bool is_left = calculate_left<mean, N, x>::value;
static const int value = static_root_helper<x, N, (is_left ? low : mean + 1), (is_left ? mean, high)>::value;
};
endpoint of recursion where the interval consists of only one entry:
template <int x, int N, int mid>
struct static_root_helper<x, N, mid, mid>
{
static const int value = mid;
};
helper to detect multiplication overflow (You can exchange the boost-header for c++11 constexpr-numeric_limits, I think). Returns true, if the multiplication a * b would overflow.
#include "boost/integer_traits.hpp"
template <typename T, T a, T b>
struct mul_overflow
{
static_assert(std::is_integral<T>::value, "T must be integral");
static const bool value = (a > boost::integer_traits<T>::const_max / b);
};
Now we need to implement calculate_left that calculates whether the solution of x^N is left of mean or right of mean. We want to be able to calculate arbitrary roots so a naive implementation like static_pow > x will overflow very quickly and give wrong results. Therefore we use the following scheme:
We want to calculate if x^N > B
set A = x and i = 1
if A >= B we are already finished -> A^N will surely be larger than B
will A * x overflow?
if yes -> A^N will surely be larger than B
if not -> A *= x and i += 1
if i == N, we are finished and we can do a simple comparison to B
now lets write this as metaprogram
template <int A, int N, int B>
struct calculate_left : calculate_left_helper<A, 1, A, N, B, (A >= B)> { };
template <int x, int i, int A, int N, int B, bool short_circuit>
struct calulate_left_helper
{
static const bool overflow = mul_overflow<int, x, A>::value;
static const int next = calculate_next<x, A, overflow>::value;
static const bool value = calculate_left_helper<next, i + 1, A, N, B, (overflow || next >= B)>::value;
};
endpoint where i == N
template <int x, int A, int N, int B, bool short_circuit>
struct calculate_left_helper<x, N, A, N, B, short_circuit>
{
static const bool value = (x >= B);
};
endpoints for short-circuit
template <int x, int i, int A, int N, int B>
struct calculate_down_helper<x, i, A, N, B, true>
{
static const bool value = true;
};
template <int x, int A, int N, int B>
struct calculate_down_helper<x, N, A, N, B, true>
{
static const bool value = true;
};
helper to calculate the next value of x * A, takex overflow into account to eliminate compiler warnings:
template <int a, int b, bool overflow>
struct calculate_next
{
static const int value = a * b;
};
template <int a, int b>
struct calculate_next<a, b, true>
{
static const int value = 0; // any value will do here, calculation will short-circuit anyway
};
So, that should be it. We need an additional helper
template <int x, int N>
struct has_integral_root
{
static const int root = static_root<x, N>::value;
static const bool value = (static_pow<root, N>::value == x);
};
Now we can implement ratio_pow as follows:
template <typename, typename> struct ratio_pow;
template <int N1, int D1, int N2, int D2>
struct ratio_pow<std::ratio<N1, D1>, std::ratio<N2, D2>>
{
// ensure that all roots are integral
static_assert(has_integral_root<std::ratio<N1, D1>::num, std::ratio<N2, D2>::den>::value, "numerator has no integral root");
static_assert(has_integral_root<std::ratio<N1, D1>::den, std::ratio<N2, D2>::den>::value, "denominator has no integral root");
// calculate the "D2"-th root of (N1 / D1)
static const int num1 = static_root<std::ratio<N1, D1>::num, std::ratio<N2, D2>::den>::value;
static const int den1 = static_root<std::ratio<N1, D1>::den, std::ratio<N2, D2>::den>::value;
// exchange num1 and den1 if the exponent is negative and set the exp to the absolute value of the exponent
static const bool positive_exponent = std::ratio<N2, D2>::num >= 0;
static const int num2 = positive_exponent ? num1 : den1;
static const int den2 = positive_exponent ? den1 : num1;
static const int exp = positive_exponent ? std::ratio<N2, D2>::num : - std::ratio<N2, D2>::num;
//! calculate (num2 / den2) ^ "N2"
typedef std::ratio<static_pow<num2, exp>::value, static_pow<den2, exp>::value> type;
};
So, I hope at least the basic idea comes across.

Yes, it's possible.
Let's define R1 = P1/Q1, R2 = P2/Q2, and R1^R2 = R3 = P3/Q3. Assume further that P and Q are co-primes.
R1^R2 = R1^(P2/Q2) = R3
R1 ^ P2 = R3 ^ Q2.
R1^P2 is known and has a unique factoring into primes 2^a * 3^b * 5^c * ... Note that a, b, c can be negative as R1 is P1/Q1. Now the first question is whether all of a,b,c are multiples of known factor Q2. If not, then you fail directly. If they are, then R3 = 2^(a/Q2) * 3^(b/Q2) * 5^(c/Q2) ....
All divisions are either exact or the result does not exist, so we can use pure integer math in our templates. Factoring a number is fairly straightforward in templates (partial specialization on x%y==0).
Example: 2^(1/2) = R3 -> a=1, b=0, c=0, ... and a%2 != 0 -> impossible. (1/9)^(1/2) -> a=0, b=-2, b%2 = 0, possible, result = 3^(-2/2).

Related

generic-template function always returning integer values

I am writing the below linear interpolation function, which is meant to be generic, but current result is not.
The function finds desired quantity of equally distant points linear in between two given boundary points. Both desired quantity and boundaries are given as parameters. As return, a vector of linear interpolated values is returned.
The issue I have concerns to return type, which always appear to be integer, even when it should have some mantissa, for example:
vec = interpolatePoints(5, 1, 4);
for (auto val : vec) std::cout << val << std::endl; // prints 4, 3, 2, 1
But it should have printed: 4.2, 3.4, 2.6, 1.8
What should I do to make it generic and have correct return values?
code:
template <class T>
std::vector<T> interpolatePoints(T lower_limit, T high_limit, const unsigned int quantity) {
auto step = ((high_limit - lower_limit)/(double)(quantity+1));
std::vector<T> interpolated_points;
for(unsigned int i = 1; i <= quantity; i++) {
interpolated_points.push_back((std::min(lower_limit, high_limit) + (step*i)));
}
return interpolated_points;
}
After some simplifications the function might look like:
template<typename T, typename N, typename R = std::common_type_t<double, T>>
std::vector<R> interpolate(T lo_limit, T hi_limit, N n) {
const auto lo = static_cast<R>(lo_limit);
const auto hi = static_cast<R>(hi_limit);
const auto step = (hi - lo) / (n + 1);
std::vector<R> pts(n);
const auto gen = [=, i = N{0}]() mutable { return lo + step * ++i; };
std::generate(pts.begin(), pts.end(), gen);
return pts;
}
The type of elements in the returned std::vector is std::common_type_t<double, T>. For int, it is double, for long double, it is long double. double looks like a reasonable default type.
You just have to pass correct type:
auto vec = interpolatePoints(5., 1., 4); // T deduced as double
Demo
And in C++20, you might use std::lerp, to have:
template <class T>
std::vector<T> interpolatePoints(T lower_limit, T high_limit, const unsigned int quantity) {
auto step = 1 / (quantity + 1.);
std::vector<T> interpolated_points;
for(unsigned int i = 1; i <= quantity; i++) {
interpolated_points.push_back(std::lerp(lower_limit, high_limit, step * i));
}
return interpolated_points;
}
Demo

how does c++ meta-programming unroll loops?

I am trying to optimize my math calculation code base and I found this piece of code from here
this piece of code tries to calculate the matrix multiplication. However, I don't understand how enum can be used for calculation here. Cnt is a type specified in
template <int I=0, int J=0, int K=0, int Cnt=0>
and somehow we can still do
Cnt = Cnt + 1
Could anyone give me a quick tutorial on how this could be happening?
Thanks
template <int I=0, int J=0, int K=0, int Cnt=0> class MatMult
{
private :
enum
{
Cnt = Cnt + 1,
Nextk = Cnt % 4,
Nextj = (Cnt / 4) % 4,
Nexti = (Cnt / 16) % 4,
go = Cnt < 64
};
public :
static inline void GetValue(D3DMATRIX& ret, const D3DMATRIX& a, const D3DMATRIX& b)
{
ret(I, J) += a(K, J) * b(I, K);
MatMult<Nexti, Nextj, Nextk, Cnt>::GetValue(ret, a, b);
}
};
// specialization to terminate the loop
template <> class MatMult<0, 0, 0, 64>
{
public :
static inline void GetValue(D3DMATRIX& ret, const D3DMATRIX& a, const D3DMATRIX& b) { }
};
Or maybe I should ask more specifically, how does Nexti, Nextj, Nextk, Cnt get propagated to the next level when the for loop is unrolled.
thanks

Initializing double at compile-time

I'm writting a compile-time implementation of floating-point arithmetic through template metaprogramming. My implementation has the following characteristics:
16 bit signed integer exponent.
32 bit unsigned integer mantissa, with no implicit most significant 1 (Thats done to simplify debugging).
The type is as follows:
template<bool S , std::int16_t E , std::uint32_t M>
struct number
{
static constexpr const bool sign = S;
static constexpr const std::int16_t exponent = E;
static constexpr const std::uint32_t mantissa = M;
};
The operations work well, but now I need a method to extract those values at compile-time and get the corresponding double values. Since the goal of compile-time arithmetic is to speed up computation injecting the solutions directly on the executable, I need a way to effectively initialize a double constant at compile-time.
So simple solutions involving std::pow( 2.0 , E ) are not allowed.
As far I know double-precission IEE754 floats have a 10 bit signed exponent and a 53 bit wide unsigned integer mantissa. My attemped solution was to use type punning via an union:
template<bool S , std::int16_t E , std::uint32_t M>
struct to_runtime<tml::floating::number<S,E,M>>
{
static constexpr const long unsigned int mantissa = M << (53 - 32);
static constexpr const int exponent = E + (53 - 32);
struct double_parts
{
unsigned int sign : 1;
int exponent : 10;
long unsigned int mantissa : 53;
};
union double_rep
{
double d;
double_parts parts;
};
static constexpr const double_parts parts = { .sign = ((bool)S) ? 0 : 1 , .exponent = exponent , .mantissa = mantissa };
static constexpr const double_rep rep = { .parts = parts };
static constexpr double execute()
{
return rep.d;
}
};
But this solution is not portable, invokes undefined behaviour (Since when doing type punning we read the member of the union which has not been written), and also I have some issues when realizing the conversion (This solution doesn't return the correct number).
Is there any other way to initialize a double at compile-time given my data (sign, exponent, mantissa)?
You may implement a constexpr pow2(std::int16_t), something like:
constexpr double pow2(std::int16_t e)
{
return e == 0 ? 1. :
e > 0 ? 2. * pow2(std::int16_t(e - 1)) :
0.5 * pow2(std::int16_t(e + 1));
}
or
constexpr double pow2(std::int16_t e)
{
return e == 0 ? 1. :
((e & 1) ? (e > 0 ? 2. : 0.5) : 1.)
* pow2(std::int16_t(e / 2))
* pow2(std::int16_t(e / 2));
}
And then
template<bool S , std::int16_t E , std::uint32_t M>
struct number
{
static constexpr const double value = (sign ? -1. : 1.) * M * pow2(E);
};
Live example

Can I generate a constant array of size n

I want to generate a constant array power[501] = {1, p % MODER, p*p % MODER, p*p*p % MODER, ..., p^500 % MODER}, of which p is an constant number.
I know I could generate p^n % MODER by using the following code:
template<int a, int n> struct pow
{
static const int value = a * pow<a, n-1>::value % MODER;
};
template<int a> struct pow<a, 0>
{
static const int value = 1;
};
And it does work!
My question is if I could generate the array that I want?
You can use BOOST_PP_ENUM as:
#include <iostream>
#include <boost/preprocessor/repetition/enum.hpp>
#define MODER 10
template<int a, int n> struct pow
{
static const int value = a * pow<a, n-1>::value % MODER;
};
template<int a> struct pow<a, 0>
{
static const int value = 1;
};
#define ORDER(count, i, data) pow<data,i>::value
int main() {
const int p = 3;
int const a[] = { BOOST_PP_ENUM(10, ORDER, p) };
std::size_t const n = sizeof(a)/sizeof(int);
for(std::size_t i = 0 ; i != n ; ++i )
std::cout << a[i] << "\n";
return 0;
}
Output:
1
3
9
7
1
3
9
7
1
3
See online demo
The line:
int const a[] = { BOOST_PP_ENUM(10, ORDER, p) };
expands to this:
int const a[] = { pow<p,0>::value, pow<p,1>::value, ...., pow<p,9>::value};
Unless n has an upper bound, I would presume that that is impossible. Check this question out. There are ways to make the preprocessor look like a Turing-complete machine but only if you accept the fact that your code size should increase in the order of n, which is not better than placing a precomputed array by hand.
Important Update: You should see this question too. It seems that not the preprocessor but the template engine is indeed Turing-complete (at least can do recursion). So, now I suspect that the answer is yes.

c++, how randomly with given probabilities choose numbers

I have N numbers n_1, n_2, ...n_N and associated probabilities p_1, p_2, ..., p_N.
function should return number n_i with probability p_i, where i =1, ..., N.
How model it in c++?
I know it is not a hard problem. But I am new to c++, want to know what function will you use.
Will you generate uniform random number between 0 and 1 like this:
((double) rand() / (RAND_MAX+1))
This is very similar to the answer I gave for this question:
changing probability of getting a random number
You can do it like this:
double val = (double)rand() / RAND_MAX;
int random;
if (val < p_1)
random = n_1;
else if (val < p_1 + p_2)
random = n_2;
else if (val < p_1 + p_2 + p_3)
random = n_3;
else
random = n_4;
Of course, this approach only makes sense if p_1 + p_2 + p_3 + p_4 == 1.0.
This can easily be generalized to a variable number of outputs and probabilities with a couple of arrays and a simple loop.
If you know the probabilities compile-time you can use this variadic template version I decided to create. Although in actuality, I don't recommend using this due to how horribly incomprehensible the source is :P.
Usage
NumChooser <
Entry<2, 10>, // Value of 2 and relative probability of 10
Entry<5, 50>,
Entry<6, 80>,
Entry<20, 01>
> chooser;
chooser.choose(); // Returns the number 2 on average 10/141 times, etc.
Efficiency
Ideone
Generally, the template based implementation is very similar to a basic one. However, there are a few differences:
With -O2 optimizations or no optimizations, the template version can be ~1-5% slower
With -O3 optimizations, the template version was actually ~1% faster when generating numbers for 1 - 10,000 times consecutively.
Notes
This uses rand() for choosing numbers. If being statistically accurate is important to you or you would like to use C++11's <random>, you can use the slightly modified version below the first source.
Source
Ideone
#define onlyAtEnd(a) typename std::enable_if<sizeof...(a) == 0 > ::type
template<int a, int b>
class Entry
{
public:
static constexpr int VAL = a;
static constexpr int PROB = b;
};
template<typename... EntryTypes>
class NumChooser
{
private:
const int SUM;
static constexpr int NUM_VALS = sizeof...(EntryTypes);
public:
static constexpr int size()
{
return NUM_VALS;
}
template<typename T, typename... args>
constexpr int calcSum()
{
return T::PROB + calcSum < args...>();
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int calcSum()
{
return 0;
}
NumChooser() : SUM(calcSum < EntryTypes... >()) { }
template<typename T, typename... args>
constexpr int find(int left, int previous = 0)
{
return left < 0 ? previous : find < args... >(left - T::PROB, T::VAL);
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int find(int left, int previous)
{
return previous;
}
constexpr int choose()
{
return find < EntryTypes... >(rand() % SUM);
}
};
C++11 <random> version
Ideone
#include <random>
#define onlyAtEnd(a) typename std::enable_if<sizeof...(a) == 0 > ::type
template<int a, int b>
class Entry
{
public:
static constexpr int VAL = a;
static constexpr int PROB = b;
};
template<typename... EntryTypes>
class NumChooser
{
private:
const int SUM;
static constexpr int NUM_VALS = sizeof...(EntryTypes);
std::mt19937 gen;
std::uniform_int_distribution<> dist;
public:
static constexpr int size()
{
return NUM_VALS;
}
template<typename T, typename... args>
constexpr int calcSum()
{
return T::PROB + calcSum < args...>();
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int calcSum()
{
return 0;
}
NumChooser() : SUM(calcSum < EntryTypes... >()), gen(std::random_device{}()), dist(1, SUM) { }
template<typename T, typename... args>
constexpr int find(int left, int previous = 0)
{
return left < 0 ? previous : find < args... >(left - T::PROB, T::VAL);
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int find(int left, int previous)
{
return previous;
}
int choose()
{
return find < EntryTypes... >(dist(gen));
}
};
// Same usage as example above
Perhaps something like (untested code!)
/* n is the size of tables, numtab[i] the number of index i,
probtab[i] its probability; the sum of all probtab should be 1.0 */
int random_inside(int n, int numtab[], double probtab[])
{
double r = drand48();
double p = 0.0;
for (int i=0; i<n; i++) {
p += probtab[i];
if (r>=p) return numtab[i];
}
}
Here you have a correct answer in my last comment:
how-to-select-a-value-from-a-list-with-non-uniform-probabilities