用等距值填充std :: vector <double>的最简单方法

时间:2016-08-26 09:27:27

标签: c++ stl stdvector

假设我有值double startdouble end和步长double step

只要当前值小于std::vector<double>,最简单的方法是将start填入stepsize的值并按end递增?

我问自己,如果有一个stl函数使这个任务成为一个单行。

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}
}

3 个答案:

答案 0 :(得分:3)

再次出于学术兴趣,可能会将std::iota的预期设计弯曲到断点:

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

使用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;
};

测试程序:

#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, ", "));
}

预期结果:

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

更新

或者我们可以构建一个自定义迭代器,它允许我们表达序列 真正的一线:

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

如下:

#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, ", "));
}

现在我们甚至不需要中间载体:

std::copy(double_inc_iterator(min, step),
          double_inc_iterator(max),
          std::ostream_iterator<double>(std::cout, ", "));

答案 1 :(得分:1)

出于学术目的,您可以:

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; });

答案 2 :(得分:0)

可以使用std::partial_sum

完成此操作
#include <vector>
#include <numeric>
#include <iterator>
#include <limits>
#include <cstddef>
#include <stdexcept>
#include <iostream>

namespace detail {
    template <typename T, typename S>
    constexpr bool is_end_reachable(const T start, const T end, const S step) noexcept
    {
        return (end > start && step > 0) || start == end || (end < start && step < 0);
    }

    template <typename T, typename S>
    constexpr std::size_t num_values(const T start, const T end, const S step) noexcept
    {
        // Add one as start is always included. Add epsilon to avoid floating point errors.
        return (((end - start) + std::numeric_limits<T>::epsilon()) / step) + 1;
    }
} // namespace detail

template <typename T, typename S>
std::vector<T> range(const T start, const T end, const S step = 1)
{
    if (!detail::is_end_reachable(start, end, step)) {
        throw std::invalid_argument {"end not reachable from start"};
    }
    std::vector<T> result(detail::num_values(start, end, step), step);
    result.front() = start;
    std::partial_sum(std::cbegin(result), std::cend(result), std::begin(result));
    return result;
}

完整类型的稳健性需要一些额外的强制转换,但想法是一样的。

示例:

int main()
{
    const auto v = range(-0.1, -2.7, -0.3312);
    std::copy(std::cbegin(v), std::cend(v), std::ostream_iterator<double> {std::cout, " "});
    std::cout << std::endl;
}

<强> Live On Coliru