Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Easiest way to fill std::vector<double> with equidistant values

Tags:

c++

stl

stdvector

Assume that I have the values double start, double end and a stepsize double step.

What is the easiest way to fill std::vector<double> with values beginning at start and incrementing by stepsize as long as the current value is less than end?

I'm asking myself, if there is an stl function making this task a one-liner.

std::vector<double> fill(double start, double end, double step) {
  // Code
}

main() {
  auto ret=fill(0.2, 2.3, 0.2);
  // ret = {0.2, 0.4, 0.6, ... , 2.2}
}
like image 644
Aleph0 Avatar asked Mar 12 '23 07:03

Aleph0


2 Answers

again out of academic interest, and probably bending the intended design of std::iota to breaking point:

std::iota(x.begin(), x.end(), double_iota(step, min));

With the following definition of double_iota:

struct double_iota
{
    double_iota(double inc, double init_value = 0.0) : _value(init_value), _inc(inc) {}

    operator double() const { return _value; }
    double_iota& operator++() { _value += _inc; return *this; }
    double _value;
    double _inc;
};

Test program:

#include <algorithm>
#include <numeric>
#include <vector>
#include <iostream>
#include <iterator>

struct double_iota
{
    double_iota(double inc, double init_value = 0.0) : _value(init_value), _inc(inc) {}

    operator double() const { return _value; }
    double_iota& operator++() { _value += _inc; return *this; }
    double _value;
    double _inc;
};

int main()
{
    double min = 1.0;
    double max = 2.3;
    double step = 0.2;

    std::vector<double> x(std::size_t(((max + step - std::numeric_limits<double>::epsilon()) - min) / step));
    std::iota(x.begin(), x.end(), double_iota(step, min));

    std::copy(x.begin(), x.end(), std::ostream_iterator<double>(std::cout, ", "));
}

expected results:

1, 1.2, 1.4, 1.6, 1.8, 2, 2.2, 

update:

or we can build a custom iterator which allows us to express the sequence truly in one line:

    std::vector<double> x(double_inc_iterator(min, step), double_inc_iterator(max));

as follows:

#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>


struct double_inc_iterator : std::iterator<std::forward_iterator_tag, double>
{
    double_inc_iterator(double initial, double inc = 1.0) : _value(initial), _inc(inc) {}
    value_type operator*() const { return _value; }
    double_inc_iterator& operator++() { _value += _inc; return *this; }

    bool operator==(double_inc_iterator const& r) const { return _value >= r._value; }
    bool operator!=(double_inc_iterator const& r) const { return !(*this == r); }

    value_type _value;
    value_type _inc;
};

int main()
{
    double min = 1.0;
    double max = 2.3;
    double step = 0.2;

    std::vector<double> x(double_inc_iterator(min, step), double_inc_iterator(max));

    std::copy(x.begin(), x.end(), std::ostream_iterator<double>(std::cout, ", "));
}

Now we don't even need the intermediate vector:

std::copy(double_inc_iterator(min, step),
          double_inc_iterator(max),
          std::ostream_iterator<double>(std::cout, ", "));
like image 131
Richard Hodges Avatar answered Apr 30 '23 14:04

Richard Hodges


Just for academic purposes, you could:

std::vector<double> result;
std::generate_n(std::back_inserter(result), (size_t)((end-start)/step), [&start, step](){ auto ret=start; start+=step; return ret; });
like image 22
Smeeheey Avatar answered Apr 30 '23 14:04

Smeeheey