функция диапазона, подобная python, но для C 17 (двойная)

#c #algorithm #c 17

Вопрос:

Я пытаюсь создать функцию, которая заполняет мой вектор значениями от начала до конца определенным шагом. Для типа 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…

Комментарии:

1. Проверьте пример: en.cppreference.com/w/cpp/iterator/iterator

2. Вы говорите, что это был бы простой цикл для int. Можете ли вы показать, как это будет выглядеть, и описать, что, по вашему мнению, будет мешать адаптации к работе для двойников?

3. @nathan-пирсон Поскольку числа с плавающей запятой представляют реальные числа, часто ошибочно полагают, что они могут точно представлять любую простую дробь. Мы можем использовать double in для цикла.

4. Учитывая , что вы могли бы написать это для int , я подозреваю, что если бы вы попытались написать то же самое для double , у вас либо все получилось бы, либо возник бы более конкретный вопрос о том, почему ваш код не идеален.

5. Попробуйте продумать, каков ваш желаемый результат. Попробуйте написать реализацию, которая его создает. Если у вас есть проблемы, спросите об этих конкретных проблемах.

Ответ №1:

Вы можете, например, написать простой цикл для генерации нужного вам вектора.

Однако range функция в python возвращает не список, а генератор, что намного быстрее. Вы также должны возвращать генератор (диапазон) в 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 amp;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 amp;value: generate_range(10, 12, 0.5))
  {
    std::cout << value << ' ';
  }
  std::cout << 'n'; // 10 10.5 11 11.5 12
  for(const auto amp;value: generate_range(239.99, 237.36, 1))
  {
    std::cout << value << ' ';
  }
  std::cout << 'n'; // 237.36 238.36 239.36
  return 0;
}
 

Обратите внимание, что != на самом деле тесты <= ; это некрасиво, но это работает.

Эта функция возвращает то, что предлагает, begin() и end() функции-члены, чтобы цикл поиска диапазона мог ее использовать.

правка: добавлена минимальная/максимальная для инвертированных границ.

Комментарии:

1. thx так много, но я пробую эти данные, и они не работают: generate_range(239.99, 237.36, 1) Я ожидал увидеть 238, Но программа ничего не отображала

2. Ах, ты тоже хочешь, чтобы все пошло в обратном направлении?

3. @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 amp;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 << ' ';
}
 

если у вас есть какие-либо вопросы о функциях, которые я использовал, не стесняйтесь спрашивать 🙂