【问题标题】:range function like python but for C++ 17 (double)范围函数,如 python,但适用于 C++ 17(双精度)
【发布时间】:2021-08-24 18:27:11
【问题描述】:

我正在尝试创建一个函数,该函数通过某个步骤从头到尾用值填充我的向量。对于 double 类型和 C++ 17 版本。知道怎么做吗?

vector<double> generateRange(double start, double end, double step)
{


}

int main()
{
    // return [10, 10.5, 11,...., 12]
    auto range = generateRange(10, 12, 0.5);

    for (auto i : range)
        std::cout << i << ' ';
}

对于 int 这将是一个非常简单的循环,但对于 double...

【问题讨论】:

  • 你说这将是一个简单的 int 循环。您能否展示一下它的外观并描述您认为使其适用于双打的症结所在?
  • @nathan-pierson 因为浮点数表示实数,所以经常错误地认为它们可以精确地表示任何简单的分数。我们可以在 for 循环中使用 double。
  • 鉴于您可以为 int 编写此代码,我怀疑如果您尝试double 编写相同代码,您要么成功,要么获得 更具体的关于为什么你的代码不完美的问题。
  • 试着想想你想要的输出是什么。尝试编写一个产生它的实现。如果您有问题,请询问这些具体问题。

标签: c++ algorithm c++17


【解决方案1】:

例如,您可以编写一个简单的循环来生成您想要的向量。

但是,python 中的range 函数返回的不是列表而是生成器,这要快得多。您还应该在 C++ 中返回一个生成器(范围),而不是返回一个向量。实现生成器要高级一些。

标准库附带了可用于构建此类生成器的工具。这是您的示例:

auto step_fun = [=](auto x) { return x * step + start; };
auto end_pred = [=](auto x) { return x <= end; };
auto range =
    std::views::iota(0)
    | std::views::transform(step_fun)
    | std::views::take_while(end_pred);

【讨论】:

    【解决方案2】:

    我认为您绝对不需要在迭代它们之前将值存储在向量中。

    我会做这样的事情

    /**
      g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
          -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
          -g -O0 -UNDEBUG -fsanitize=address,undefined
    **/
    
    #include <iostream>
    #include <algorithm>
    
    inline
    auto // iterable
    generate_range(double from_count,
                   double to_count,
                   double step)
    {
      struct Iter
      {
        double count;
        double step;
        bool operator!=(const double &rhs) const { return count<=rhs; } // oh!!!
        void operator++() { count+=step; }
        auto operator*() const { return count; }
      };
      struct Enumerate
      {
        double from_count;
        double to_count;
        double step;
        auto begin() { return Iter{from_count, step}; }
        auto end() { return to_count; }
      };
      return Enumerate{std::min(from_count, to_count),
                       std::max(from_count, to_count),
                       step};
    }
    
    int
    main()
    {
      for(const auto &value: generate_range(10, 12, 0.5))
      {
        std::cout << value << ' ';
      }
      std::cout << '\n'; // 10 10.5 11 11.5 12
      for(const auto &value: generate_range(239.99, 237.36, 1))
      {
        std::cout << value << ' ';
      }
      std::cout << '\n'; // 237.36 238.36 239.36
      return 0;
    }
    

    注意!=实际上测试&lt;=;这很丑陋,但它有效。

    此函数返回提供 begin()end() 成员函数的内容,以便 range-for 循环可以使用它。

    编辑:为倒置边界添加了最小值/最大值。

    【讨论】:

    • 非常感谢,但我尝试了这个数据,但它不起作用: generate_range(239.99, 237.36, 1) 我希望看到 238 但程序没有显示任何内容
    • 啊,你也想倒退吗?
    • @SergoLongid 我随后进行了编辑,但我不确定您的确切期望。
    【解决方案3】:

    我的问题解决方案:

    #include <vector>
    using std::vector;
    #include <iostream>
    using std::cout;
    #include <algorithm>
    
    vector<double> generateRange(double start, double end, double step)
    {
        int vector_size = (end - start) / step;
        vector<double> values(vector_size);
        std::for_each(begin(values), std::end(values),
        [start, step, i = 0](double &actual) mutable {
            actual = start + step * i;
            i++;
        });
        return values;
    
    }
    
    int main()
    {
        // return [10, 10.5, 11,...., 12]
        auto range = generateRange(10, 12, 0.5);
    
        for (auto i : range)
            std::cout << i << ' ';
    }
    

    如果您对我使用的功能有任何疑问,请不要犹豫:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-07
      • 2014-05-27
      • 2021-12-19
      • 2014-01-20
      • 1970-01-01
      相关资源
      最近更新 更多