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
Related
Is it possible to create a vector from a value to another one with a fixed step without using a loop in c++?
For example, I want to build a vector from 1 to 10 with step 0.5. In MATLAB I can do this as follow:
vector = [1:0.5:10];
Is there something similar in c++?
With the help of std::generate_n you can
std::vector<double> v;
const int size = 10 * 2 - 1;
v.reserve(size);
std::generate_n(std::back_inserter(v), size, []() { static double d = 0.5; return d += 0.5; });
LIVE
You need a loop somewhere. Matlab is simply hiding the loop from you. If this is something you do often, just create a function to make it easier to use:
#include <vector>
auto make_vector(double beg, double step, double end)
{
std::vector<double> vec;
vec.reserve((end - beg) / step + 1);
while (beg <= end) {
vec.push_back(beg);
beg += step;
}
return vec;
}
int main() {
auto vec = make_vector(1, 0.5, 10);
}
It's not possible without a loop, but you can hide the loop by using e.g, std::generate or std::generate_n:
constexpr size_t SIZE = (10 - 1) * 2;
std::vector<double> data(SIZE);
double new_value = 1.0;
std::generate(begin(data), end(data) [&new_value]()
{
double current_value = new_value;
new_value += 0.5;
return current_value;
});
Of course, this is quite a lot to write, and an explicit loop would probably be better:
std::vector<double> data;
for (double i = 1.0; i <= 10; i += 0.5)
data.push_back(i);
If the stepping is "one" (e.g. 1 or 1.0) then you could use std::iota instead:
std::vector<double> data(10);
std::iota(begin(data), end(data), 1.0); // Initializes the vector with values from 1.0 to 10.0
No, there is no such things in C++. You will have to create a loop and populate your vector, so something like:
std::vector<double> v;
v.reserve(19);
for(size_t i = 2; i < 21; ++i)
{
v.push_back(i / 2.);
}
I'm using here an integer loop instead of a double loop with .5 increments to make sure about the number of elements I get and minimize numerical rounding errors (.5 is fine, but not 1/3 for instance).
A simple solution using Ranges-v3 library:
#include <range/v3/all.hpp>
auto make_vector(double min, double step, double max) {
const auto size = static_cast<std::size_t>((max - min) / step);
return ranges::views::iota(std::size_t{0}, size + 1) |
ranges::views::transform([min, step](auto i) { return min + step * i; }) |
ranges::to<std::vector>();
}
int main() {
auto vec = make_vector(1, .5, 5);
for (auto x : vec)
std::cout << x << ' ';
// Output: 1 1.5 2 2.5 3 3.5 4 4.5 5
}
Ranges will be a part of C++20.
If you need to do a lot of this, you can easily write your own function that can work with any container (that supports reserve and is fill-able by std::generate):
template <typename TContainer>
TContainer fill(typename TContainer::value_type start,
typename TContainer::value_type step,
typename TContainer::value_type end) {
size_t size = static_cast<size_t>((end - start)/step + 1);
TContainer output(size);
std::generate(std::begin(output), std::end(output),
[&start, step]() {
return std::exchange(start, start + step);
}
);
return output;
}
Then you can use it as follows:
auto vec = fill<std::vector<int>>(0, 2, 10);
auto list = fill<std::list<float>>(1, 0.3, 5);
Live example
And you will get:
vec: 0, 2, 4, 6, 8, 10
list: 1, 1.3, 1.6, 1.9, 2.2, 2.5, 2.8, 3.1, 3.4, 3.7, 4, 4.3, 4.6, 4.9
I would like to generate Pascal pyramid data from a given data set that looks like this
Pyramid(1,2,3,4,5,6,7,8,9);
This is what I have been doing but it reaches only the second layer while I want it to recursively loop till the top.
template<typename T>
const T Pyramid(T a, T b)
{
return a + b;
}
template<typename T, typename ...A>
const T Pyramid(T t1, T t2, A...a)
{
return Pyramid(t1, t2) + Pyramid(t2, a...);
}
Could you help me fill up the next layers ? ;)
C++17
Here is the C++17 solution (using fold expressions):
#include <iostream>
#include <stdexcept>
#include <utility>
using Integer = std::uint64_t;
constexpr auto Factorial(const Integer n)
{
Integer factorial = 1;
for (Integer i = 2; i <= n; ++i)
{
factorial *= i;
}
return factorial;
}
constexpr auto Binom(const Integer n, const Integer m)
{
if (n < m)
{
throw std::invalid_argument("Binom: n should not be less than m");
}
return Factorial(n) / Factorial(m) / Factorial(n - m);
}
template <Integer... indices, typename... Types>
constexpr auto PyramidImplementation(std::integer_sequence<Integer, indices...>, Types... values)
{
return ((Binom(sizeof...(values), indices) * values) + ...);
}
template <typename... Types>
constexpr auto Pyramid(Types... values)
{
return PyramidImplementation(std::make_integer_sequence<Integer, sizeof...(values)>{}, values...);
}
// ...
constexpr auto pyramid = Pyramid(1, 2, 3, 4, 5, 6, 7, 8, 9);
std::cout << "Pyramid = " << pyramid << std::endl;
Live demo
This solution doesn't use the recursion, because the needed result for a[i] (i = 0 ... n - 1) can be calculated as a sum of binom(n, i) * a[i] (for i = 0 ... n - 1), where binom(n, m) is the binomial coefficient. The Binom function is implemented in the simplest way, so it will work only for small values of n.
C++14
The code can be made C++14-compatible via the following PyramidImplementation function implementation:
#include <type_traits>
template <Integer... indices, typename... Types>
constexpr auto PyramidImplementation(std::integer_sequence<Integer, indices...>, Types... values)
{
using Do = int[];
std::common_type_t<Types...> pyramid{};
(void)Do{0, (pyramid += Binom(sizeof...(values), indices) * values, 0)...};
return pyramid;
}
Live demo
I'm trying to learn how to use lamba functions, and want to do something like:
Given a vector = {1,2,3,4,5}
I want the sum of pairwise sums = (1+2)+(2+3)+...
Below is my attempt, which is not working properly.
#include <vector>
#include <algorithm>
using namespace std;
vector <double> data = {1,10,100};
double mean = accumulate(data.begin(),data.end(),0.0);
double foo()
{
auto bar = accumulate(data.begin(),data.end(),0.0,[&](int k, int l){return (k+l);});
return bar
}
I tried changing the return statement to return (data.at(k)+data.at(l)), which didn't quite work.
Adding pairwise sums is the same as summing over everything twice except the first and last elements. No need for a fancy lambda.
auto result = std::accumulate(std::begin(data), std::end(data), 0.0)
* 2.0 - data.front() - data.end();
Or a little safer:
auto result = std::accumulate(std::begin(data), std::end(data), 0.0)
* 2.0 - (!data.empty() ? data.front() : 0) - (data.size() > 1 ? data.back() : 0);
If you insist on a lambda, you can move the doubling inside:
result = std::accumulate(std::begin(data), std::end(data), 0.0,
[](double lhs, double rhs){return lhs + 2.0*rhs;})
- data.front() - data.back();
Note that lhs within the lambda is the current sum, not the next two numbers in the sequence.
If you insist on doing all the work within the lambda, you can track an index by using generalized capture:
result = std::accumulate(std::begin(data), std::end(data), 0.0,
[currIndex = 0U, lastIndex = data.size()-1] (double lhs, double rhs) mutable
{
double result = lhs + rhs;
if (currIndex != 0 && currIndex != lastIndex)
result += rhs;
++currIndex;
return result;
});
Demo of all approaches
You misunderstand how std::accumulate works. Let's say you have int array[], then accumulate does:
int value = initial_val;
value = lambda( value, array[0] );
value = lambda( value, array[1] );
...
return value;
this is pseudo code, but it should be pretty easy to understand how it works. So in your case std::accumulate does not seem to be applicable. You may write a loop, or create your own special accumulate function:
auto lambda = []( int a, int b ) { return a + b; };
auto sum = 0.0;
for( auto it = data.begin(); it != data.end(); ++it ) {
auto itn = std::next( it );
if( itn == data.end() ) break;
sum += lambda( *it, *itn );
}
You could capture a variable in the lambda to keep the last value:
#include <vector>
#include <algorithm>
#include <numeric>
std::vector<double> data = {1,10,100};
double mean = accumulate(data.begin(), data.end(), 0.0);
double foo()
{
double last{0};
auto bar = accumulate(data.begin(), data.end(), 0.0, [&](auto k, auto l)
{
auto total = l + last;
last = l;
return total+k;
});
return bar;
}
int main()
{
auto val = foo();
}
You could use some sort of index, and add the next number.
size_t index = 1;
auto bar = accumulate(data.begin(), data.end(), 0.0, [&index, &data](double a, double b) {
if (index < data.size())
return a + b + data[index++];
else
return a + b;
});
Note you have a vector of doubles but are using ints to sum.
I want to fill a vector<float> with values, starting from a, increasing by inc, up to and including b. So basically what e.g. vec = 2:0.5:4 in Matlab would do - vec should now be { 2.0, 2.5, 3.0, 3.5, 4.0 }.
The best I could come up with is
vector<float> vec(10);
float increment = 0.5f;
std::generate(begin(vec), end(vec), [&increment]() {static float start = 2.0f; return start += increment ; });
But obviously it is incorrect as it starts at 2.5f, not 2.0f. And I would like to specify the parameters a bit easier or more concise.
I could imagine doing it in a dedicated class, but that would require quite some code.
Also I've looked at std::iota, but it can only increase by +1.
Any ideas on the best, concise approach? Using C++11 (and some parts of 14) welcome.
Edit: Of course I've also used a for-loop like:
for (float i = -1.0f; i <= 1.0f; i += 0.05f) {
vec.emplace_back(i);
}
but it has the problem that it sometimes doesn't go up to the end value, as in this example, because of float impreciseness (or rather representation). Fixing that requires some code and I think there should be a more concise way?
You could write your own variant of std::iota that also accepts a stride argument.
template<typename ForwardIterator, typename T>
void strided_iota(ForwardIterator first, ForwardIterator last, T value, T stride)
{
while(first != last) {
*first++ = value;
value += stride;
}
}
In your example, you'd use it as
std::vector<float> vec(10);
strided_iota(std::begin(vec), std::next(std::begin(vec), 5), 2.0f, 0.5f);
Live demo
I don't think you really need any fancy features for this.
void fill_vec(vector<float>& vec, float a, float inc, float b)
{
for(float n = a; n <= b; n += inc)
vec.push_back(n);
}
If you're worried about floating point precision missing the upper range, then you can add a small amount (often denoted by epsilon for this sort of thing):
float eps = 0.0000001f;
for(float n = a; n <= b + eps; n += inc)
If you include <cfloat>, you can use FLT_EPSILON which may vary between platforms to suit the implementation.
If the issue is that you want to include all the float values, then loop on integers and do the necessary calculations to go back to the float value within the loop.
for (int i = 20; i <= 40; i += 5) {
vec.emplace_back(i/10.0);
}
Here is an approach:
#include <iostream>
#include <vector>
#include <algorithm>
// functor
class generator_float
{
float _start, _inc;
public:
generator_float(float start, float inc): _start(start), _inc(inc) {};
float operator()() {
float tmp = _start;
_start += _inc;
return tmp;
}
};
int main()
{
std::vector<float> vec(10);
std::generate(std::begin(vec), std::end(vec), generator_float(2,0.5));
for(auto&& elem: vec)
std::cout << elem << " ";
std::cout << std::endl;
}
You can use a functor that works for both for iota and generate. Overload the function call and increment operator appropriately:
template <typename T>
class ArithmeticProgression
{
T val;
T inc;
public:
ArithmeticProg(T val, T inc) : val(val), inc(inc) {}
ArithmeticProg& operator++() noexcept(noexcept(val += inc))
{
val += inc;
return *this;
}
T operator()() noexcept(noexcept(val += inc))
{
auto tmp = val;
val += inc;
return tmp;
}
operator T() const noexcept {return val;}
};
template <typename T, typename U>
ArProg<typename std::common_type<T, U>::type> makeArithmeticProg( T val, U inc )
{
return {val, inc};
}
Usage:
int main()
{
std::vector<float> vec;
std::generate_n(std::back_inserter(vec), 5, makeArithmeticProg(2.0f, 0.5f) );
for (auto f : vec)
std::cout << f << ", ";
std::cout << '\n';
std::iota( std::begin(vec), std::end(vec), makeArithmeticProg(2.5f, 0.3f) );
for (auto f : vec)
std::cout << f << ", ";
}
Demo.
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