How to create a `range`-like iterable object of floats?How do I iterate over the words of a string?How do I check if a string is a number (float)?How do I parse a string to a float or int in Python?How to use a decimal range() step value?How to format a float in javascript?How can I force division to be floating point? Division keeps rounding down to 0?How to deal with floating point number precision in JavaScript?How to iterate through two lists in parallel?How to get a random number between a float range?How to convert an iterator to a stream?

Building a road to escape Earth's gravity by making a pyramid on Antartica

Why is the relationship between frequency and pitch exponential?

Company did not petition for visa in a timely manner. Is asking me to work from overseas, but wants me to take a paycut

How bad would a partial hash leak be, realistically?

Why doesn’t a normal window produce an apparent rainbow?

Movie about a boy who was born old and grew young

Payment instructions from HomeAway look fishy to me

Strange symbol for two functions

Do any instruments not produce overtones?

Does there exist a word to express a male who behaves as a female?

Can a user sell my software (MIT license) without modification?

What can plausibly explain many of my very long and low-tech bridges?

What risks are there when you clear your cookies instead of logging off?

Turing patterns

How to translate “Me doing X” like in online posts?

Traffic law UK, pedestrians

How to generate random points without duplication?

When writing an error prompt, should we end the sentence with a exclamation mark or a dot?

Phone number to a lounge, or lounges generally

What is this solid state starting relay component?

Trapping Rain Water

Does the growth of home value benefit from compound interest?

2.8 is missing the Carve option in the Boolean Modifier

Version 2 - print new even-length arrays from two arrays



How to create a `range`-like iterable object of floats?


How do I iterate over the words of a string?How do I check if a string is a number (float)?How do I parse a string to a float or int in Python?How to use a decimal range() step value?How to format a float in javascript?How can I force division to be floating point? Division keeps rounding down to 0?How to deal with floating point number precision in JavaScript?How to iterate through two lists in parallel?How to get a random number between a float range?How to convert an iterator to a stream?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








24















I want to create a range-like construct in c++, that will be used like this:



for (auto i: range(5,9))
cout << i << ' '; // prints 5 6 7 8

for (auto i: range(5.1,9.2))
cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1


Handling the integer case is relatively easy:



template<typename T>
struct range

T from, to;
range(T from, T to) : from(from), to(to)

struct iterator

T current;
T operator*() return current;

iterator& operator++()

++current;
return *this;


bool operator==(const iterator& other) return current == other.current;
bool operator!=(const iterator& other) return current != other.current;
;

iterator begin() const return iterator from ;
iterator end() const return iterator to ;
;


However, this does not work in the float case, since the standard range-based loop in C++ checks whether iter==end, and not whether iter <= end as you would do in a for a loop.



Is there a simple way to create an iterable object that will behave like a correct for loop on floats?










share|improve this question
























  • Maybe a specialization of operator== for floating-point types that subverts the semantics by using current<=other.current?

    – Some programmer dude
    May 20 at 9:06






  • 8





    What about implementing a special end iterator, which would be set in operator++() when the incremented value exceeds to?

    – Daniel Langr
    May 20 at 9:12











  • Since coroutines have been mentioned, why not use the upcoming ranges library? (Or the range library that was the base for the standard?)

    – Some programmer dude
    May 20 at 9:21







  • 8





    You should be aware that floating-point rounding will affect your loop. For example, with the IEEE-754 format commonly used for double, for (double x = 1.03; x <= 11.03; x += 1) will end when x is about 10.03, not 11.03. It will be incremented to 11.030000000000001136868377216160297393798828125, but 11.03 in source code becomes the value 11.0299999999999993605115378159098327159881591796875, so x <= 11.03 evaluates to false.

    – Eric Postpischil
    May 20 at 17:41







  • 2





    It's a lot safer to use a linspace-style explicit count of elements (and no default count, unlike MATLAB or numpy linspace), rather than starting from a step value and deriving the number of elements from there. A count-oriented instead of step-size-oriented approach eliminates issues with unexpectedly including or excluding the endpoint.

    – user2357112
    May 20 at 21:41

















24















I want to create a range-like construct in c++, that will be used like this:



for (auto i: range(5,9))
cout << i << ' '; // prints 5 6 7 8

for (auto i: range(5.1,9.2))
cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1


Handling the integer case is relatively easy:



template<typename T>
struct range

T from, to;
range(T from, T to) : from(from), to(to)

struct iterator

T current;
T operator*() return current;

iterator& operator++()

++current;
return *this;


bool operator==(const iterator& other) return current == other.current;
bool operator!=(const iterator& other) return current != other.current;
;

iterator begin() const return iterator from ;
iterator end() const return iterator to ;
;


However, this does not work in the float case, since the standard range-based loop in C++ checks whether iter==end, and not whether iter <= end as you would do in a for a loop.



Is there a simple way to create an iterable object that will behave like a correct for loop on floats?










share|improve this question
























  • Maybe a specialization of operator== for floating-point types that subverts the semantics by using current<=other.current?

    – Some programmer dude
    May 20 at 9:06






  • 8





    What about implementing a special end iterator, which would be set in operator++() when the incremented value exceeds to?

    – Daniel Langr
    May 20 at 9:12











  • Since coroutines have been mentioned, why not use the upcoming ranges library? (Or the range library that was the base for the standard?)

    – Some programmer dude
    May 20 at 9:21







  • 8





    You should be aware that floating-point rounding will affect your loop. For example, with the IEEE-754 format commonly used for double, for (double x = 1.03; x <= 11.03; x += 1) will end when x is about 10.03, not 11.03. It will be incremented to 11.030000000000001136868377216160297393798828125, but 11.03 in source code becomes the value 11.0299999999999993605115378159098327159881591796875, so x <= 11.03 evaluates to false.

    – Eric Postpischil
    May 20 at 17:41







  • 2





    It's a lot safer to use a linspace-style explicit count of elements (and no default count, unlike MATLAB or numpy linspace), rather than starting from a step value and deriving the number of elements from there. A count-oriented instead of step-size-oriented approach eliminates issues with unexpectedly including or excluding the endpoint.

    – user2357112
    May 20 at 21:41













24












24








24


2






I want to create a range-like construct in c++, that will be used like this:



for (auto i: range(5,9))
cout << i << ' '; // prints 5 6 7 8

for (auto i: range(5.1,9.2))
cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1


Handling the integer case is relatively easy:



template<typename T>
struct range

T from, to;
range(T from, T to) : from(from), to(to)

struct iterator

T current;
T operator*() return current;

iterator& operator++()

++current;
return *this;


bool operator==(const iterator& other) return current == other.current;
bool operator!=(const iterator& other) return current != other.current;
;

iterator begin() const return iterator from ;
iterator end() const return iterator to ;
;


However, this does not work in the float case, since the standard range-based loop in C++ checks whether iter==end, and not whether iter <= end as you would do in a for a loop.



Is there a simple way to create an iterable object that will behave like a correct for loop on floats?










share|improve this question
















I want to create a range-like construct in c++, that will be used like this:



for (auto i: range(5,9))
cout << i << ' '; // prints 5 6 7 8

for (auto i: range(5.1,9.2))
cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1


Handling the integer case is relatively easy:



template<typename T>
struct range

T from, to;
range(T from, T to) : from(from), to(to)

struct iterator

T current;
T operator*() return current;

iterator& operator++()

++current;
return *this;


bool operator==(const iterator& other) return current == other.current;
bool operator!=(const iterator& other) return current != other.current;
;

iterator begin() const return iterator from ;
iterator end() const return iterator to ;
;


However, this does not work in the float case, since the standard range-based loop in C++ checks whether iter==end, and not whether iter <= end as you would do in a for a loop.



Is there a simple way to create an iterable object that will behave like a correct for loop on floats?







c++ floating-point iterator range






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 20 at 19:06









JeJo

5,75331028




5,75331028










asked May 20 at 9:01









Erel Segal-HaleviErel Segal-Halevi

12.8k2371121




12.8k2371121












  • Maybe a specialization of operator== for floating-point types that subverts the semantics by using current<=other.current?

    – Some programmer dude
    May 20 at 9:06






  • 8





    What about implementing a special end iterator, which would be set in operator++() when the incremented value exceeds to?

    – Daniel Langr
    May 20 at 9:12











  • Since coroutines have been mentioned, why not use the upcoming ranges library? (Or the range library that was the base for the standard?)

    – Some programmer dude
    May 20 at 9:21







  • 8





    You should be aware that floating-point rounding will affect your loop. For example, with the IEEE-754 format commonly used for double, for (double x = 1.03; x <= 11.03; x += 1) will end when x is about 10.03, not 11.03. It will be incremented to 11.030000000000001136868377216160297393798828125, but 11.03 in source code becomes the value 11.0299999999999993605115378159098327159881591796875, so x <= 11.03 evaluates to false.

    – Eric Postpischil
    May 20 at 17:41







  • 2





    It's a lot safer to use a linspace-style explicit count of elements (and no default count, unlike MATLAB or numpy linspace), rather than starting from a step value and deriving the number of elements from there. A count-oriented instead of step-size-oriented approach eliminates issues with unexpectedly including or excluding the endpoint.

    – user2357112
    May 20 at 21:41

















  • Maybe a specialization of operator== for floating-point types that subverts the semantics by using current<=other.current?

    – Some programmer dude
    May 20 at 9:06






  • 8





    What about implementing a special end iterator, which would be set in operator++() when the incremented value exceeds to?

    – Daniel Langr
    May 20 at 9:12











  • Since coroutines have been mentioned, why not use the upcoming ranges library? (Or the range library that was the base for the standard?)

    – Some programmer dude
    May 20 at 9:21







  • 8





    You should be aware that floating-point rounding will affect your loop. For example, with the IEEE-754 format commonly used for double, for (double x = 1.03; x <= 11.03; x += 1) will end when x is about 10.03, not 11.03. It will be incremented to 11.030000000000001136868377216160297393798828125, but 11.03 in source code becomes the value 11.0299999999999993605115378159098327159881591796875, so x <= 11.03 evaluates to false.

    – Eric Postpischil
    May 20 at 17:41







  • 2





    It's a lot safer to use a linspace-style explicit count of elements (and no default count, unlike MATLAB or numpy linspace), rather than starting from a step value and deriving the number of elements from there. A count-oriented instead of step-size-oriented approach eliminates issues with unexpectedly including or excluding the endpoint.

    – user2357112
    May 20 at 21:41
















Maybe a specialization of operator== for floating-point types that subverts the semantics by using current<=other.current?

– Some programmer dude
May 20 at 9:06





Maybe a specialization of operator== for floating-point types that subverts the semantics by using current<=other.current?

– Some programmer dude
May 20 at 9:06




8




8





What about implementing a special end iterator, which would be set in operator++() when the incremented value exceeds to?

– Daniel Langr
May 20 at 9:12





What about implementing a special end iterator, which would be set in operator++() when the incremented value exceeds to?

– Daniel Langr
May 20 at 9:12













Since coroutines have been mentioned, why not use the upcoming ranges library? (Or the range library that was the base for the standard?)

– Some programmer dude
May 20 at 9:21






Since coroutines have been mentioned, why not use the upcoming ranges library? (Or the range library that was the base for the standard?)

– Some programmer dude
May 20 at 9:21





8




8





You should be aware that floating-point rounding will affect your loop. For example, with the IEEE-754 format commonly used for double, for (double x = 1.03; x <= 11.03; x += 1) will end when x is about 10.03, not 11.03. It will be incremented to 11.030000000000001136868377216160297393798828125, but 11.03 in source code becomes the value 11.0299999999999993605115378159098327159881591796875, so x <= 11.03 evaluates to false.

– Eric Postpischil
May 20 at 17:41






You should be aware that floating-point rounding will affect your loop. For example, with the IEEE-754 format commonly used for double, for (double x = 1.03; x <= 11.03; x += 1) will end when x is about 10.03, not 11.03. It will be incremented to 11.030000000000001136868377216160297393798828125, but 11.03 in source code becomes the value 11.0299999999999993605115378159098327159881591796875, so x <= 11.03 evaluates to false.

– Eric Postpischil
May 20 at 17:41





2




2





It's a lot safer to use a linspace-style explicit count of elements (and no default count, unlike MATLAB or numpy linspace), rather than starting from a step value and deriving the number of elements from there. A count-oriented instead of step-size-oriented approach eliminates issues with unexpectedly including or excluding the endpoint.

– user2357112
May 20 at 21:41





It's a lot safer to use a linspace-style explicit count of elements (and no default count, unlike MATLAB or numpy linspace), rather than starting from a step value and deriving the number of elements from there. A count-oriented instead of step-size-oriented approach eliminates issues with unexpectedly including or excluding the endpoint.

– user2357112
May 20 at 21:41












4 Answers
4






active

oldest

votes


















17














Here is my attempt, which does not hamper the semantics of iterators. The change is that now, each iterator knows its stopping value, to which it will set itself upon exceeding it. All end iterators of a range with equal to therefore compare equal.



template <typename T> 
struct range
T from, to;
range(T from, T to): from(from), to(to)

struct iterator
const T to; // iterator knows its bounds
T current;

T operator*() return current;

iterator& operator++()
++current;
if(current > to)
// make it an end iterator
// (current being exactly equal to 'current' of other end iterators)
current = to;
return *this;


bool operator==(const iterator& other) const // OT: note the const
return current == other.current;
// OT: this is how we do !=
bool operator!=(const iterator& other) const return !(*this == other);
;

iterator begin() const return iteratorto, from;
iterator end() const return iteratorto, to;
;


Why is this better?



The solution by @JeJo relies on the order in which you compare those iterators, i.e. it != end or end != it. But, in the case of range-based for, it is defined. Should you use this contraption in some other context, I advise the above approach.




Alternatively, if sizeof(T) > sizeof(void*), it makes sense to store a pointer to the originating range instance (which in the case of the range-for persists until the end) and use that to refer to a single T value:



template <typename T> 
struct range
T from, to;
range(T from, T to): from(from), to(to)

struct iterator
const range* range;
T current;

iterator& operator++()
++current;
if(current > range->to)
current = range->to;
return *this;


...
;

iterator begin() const return iteratorthis, from;
iterator end() const return iteratorthis, to;
;


Or it could be T const* const pointing directly to that value, it is up to you.



OT: Do not forget to make the internals private for both classes.






share|improve this answer
































    13














    Instead of a range object you could use a generator (a coroutine using co_yield). Despite it is not in the standard (but planned for C++20), some compilers already implement it.



    See: https://en.cppreference.com/w/cpp/language/coroutines



    With MSVC it would be:



    #include <iostream>
    #include <experimental/generator>

    std::experimental::generator<double> rangeGenerator(double from, double to)
    for (double x=from;x <= to;x++)

    co_yield x;



    int main()

    for (auto i : rangeGenerator(5.1, 9.2))
    std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1






    share|improve this answer
































      8















      Is there a simple way to create an iterable object that will behave
      like a correct for loop on floats?




      The simplest hack would be using the traits std::is_floating_point to provide different return (i.e. iter <= end) within the operator!= overload.



      (See Live)



      #include <type_traits>

      bool operator!=(const iterator& other)

      if constexpr (std::is_floating_point_v<T>) return current <= other.current;
      return !(*this == other);



      Warning: Even though that does the job, it breaks the meaning of operator!= overload.




      Alternative Solution



      The entire range class can be replaced by a simple function in which the values of the range will be populated with the help of std::iota
      in the standard container std::vector.



      Use SFINE, to restrict the use of the function for only the valid types.
      This way, you can rely on standard implementations and forget about the reinventions.



      (See Live)



      #include <iostream>
      #include <type_traits>
      #include <vector> // std::vector
      #include <numeric> // std::iota
      #include <cstddef> // std::size_t
      #include <cmath> // std::modf

      // traits for valid template types(integers and floating points)
      template<typename Type>
      using is_integers_and_floats = std::conjunction<
      std::is_arithmetic<Type>,
      std::negation<std::is_same<Type, bool>>,
      std::negation<std::is_same<Type, char>>,
      std::negation<std::is_same<Type, char16_t>>,
      std::negation<std::is_same<Type, char32_t>>,
      std::negation<std::is_same<Type, wchar_t>>
      /*, std::negation<std::is_same<char8_t, Type>> */ // since C++20
      >;

      template <typename T>
      auto ragesof(const T begin, const T end)
      -> std::enable_if_t<is_integers_and_floats<T>::value, std::vector<T>>

      if (begin >= end) return std::vector<T>; // edge case to be considered
      // find the number of elements between the range
      const std::size_t size = [begin, end]() -> std::size_t

      const std::size_t diffWhole
      = static_cast<std::size_t>(end) - static_cast<std::size_t>(begin);
      if constexpr (std::is_floating_point_v<T>)
      double whole; // get the decimal parts of begin and end
      const double decimalBegin = std::modf(static_cast<double>(begin), &whole);
      const double decimalEnd = std::modf(static_cast<double>(end), &whole);
      return decimalBegin <= decimalEnd ? diffWhole + 1 : diffWhole;

      return diffWhole;
      ();
      // construct and initialize the `std::vector` with size
      std::vector<T> vec(size);
      // populates the range from [first, end)
      std::iota(std::begin(vec), std::end(vec), begin);
      return vec;


      int main()

      for (auto i : ragesof( 5, 9 ))
      std::cout << i << ' '; // prints 5 6 7 8
      std::cout << 'n';

      for (auto i : ragesof(5.1, 9.2))
      std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1






      share|improve this answer
































        5














        A floating-point loop or iterator should typically use integer types to hold the total number of iterations and the number of the current iteration, and then compute the "loop index" value used within the loop based upon those and loop-invariant floating-point values.



        For example:



        for (int i=-10; i<=10; i++)

        double x = i/10.0; // Substituting i*0.1 would be faster but less accurate



        or



        for (int i=0; i<=16; i++)

        double x = ((startValue*(16-i))+(endValue*i))*(1/16);



        Note that there is no possibility of rounding errors affecting the number of iterations. The latter calculation is guaranteed to yield a correctly-rounded result at the endpoints; computing startValue+i*(endValue-startValue) would likely be faster (since the loop-invariant (endValue-startValue) can be hoisted) but may be less accurate.



        Using an integer iterator along with a function to convert an integer to a floating-point value is probably the most robust way to iterate over a range of floating-point values. Trying to iterate over floating-point values directly is far more likely to yield "off-by-one" errors.






        share|improve this answer























          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56217541%2fhow-to-create-a-range-like-iterable-object-of-floats%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          4 Answers
          4






          active

          oldest

          votes








          4 Answers
          4






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          17














          Here is my attempt, which does not hamper the semantics of iterators. The change is that now, each iterator knows its stopping value, to which it will set itself upon exceeding it. All end iterators of a range with equal to therefore compare equal.



          template <typename T> 
          struct range
          T from, to;
          range(T from, T to): from(from), to(to)

          struct iterator
          const T to; // iterator knows its bounds
          T current;

          T operator*() return current;

          iterator& operator++()
          ++current;
          if(current > to)
          // make it an end iterator
          // (current being exactly equal to 'current' of other end iterators)
          current = to;
          return *this;


          bool operator==(const iterator& other) const // OT: note the const
          return current == other.current;
          // OT: this is how we do !=
          bool operator!=(const iterator& other) const return !(*this == other);
          ;

          iterator begin() const return iteratorto, from;
          iterator end() const return iteratorto, to;
          ;


          Why is this better?



          The solution by @JeJo relies on the order in which you compare those iterators, i.e. it != end or end != it. But, in the case of range-based for, it is defined. Should you use this contraption in some other context, I advise the above approach.




          Alternatively, if sizeof(T) > sizeof(void*), it makes sense to store a pointer to the originating range instance (which in the case of the range-for persists until the end) and use that to refer to a single T value:



          template <typename T> 
          struct range
          T from, to;
          range(T from, T to): from(from), to(to)

          struct iterator
          const range* range;
          T current;

          iterator& operator++()
          ++current;
          if(current > range->to)
          current = range->to;
          return *this;


          ...
          ;

          iterator begin() const return iteratorthis, from;
          iterator end() const return iteratorthis, to;
          ;


          Or it could be T const* const pointing directly to that value, it is up to you.



          OT: Do not forget to make the internals private for both classes.






          share|improve this answer





























            17














            Here is my attempt, which does not hamper the semantics of iterators. The change is that now, each iterator knows its stopping value, to which it will set itself upon exceeding it. All end iterators of a range with equal to therefore compare equal.



            template <typename T> 
            struct range
            T from, to;
            range(T from, T to): from(from), to(to)

            struct iterator
            const T to; // iterator knows its bounds
            T current;

            T operator*() return current;

            iterator& operator++()
            ++current;
            if(current > to)
            // make it an end iterator
            // (current being exactly equal to 'current' of other end iterators)
            current = to;
            return *this;


            bool operator==(const iterator& other) const // OT: note the const
            return current == other.current;
            // OT: this is how we do !=
            bool operator!=(const iterator& other) const return !(*this == other);
            ;

            iterator begin() const return iteratorto, from;
            iterator end() const return iteratorto, to;
            ;


            Why is this better?



            The solution by @JeJo relies on the order in which you compare those iterators, i.e. it != end or end != it. But, in the case of range-based for, it is defined. Should you use this contraption in some other context, I advise the above approach.




            Alternatively, if sizeof(T) > sizeof(void*), it makes sense to store a pointer to the originating range instance (which in the case of the range-for persists until the end) and use that to refer to a single T value:



            template <typename T> 
            struct range
            T from, to;
            range(T from, T to): from(from), to(to)

            struct iterator
            const range* range;
            T current;

            iterator& operator++()
            ++current;
            if(current > range->to)
            current = range->to;
            return *this;


            ...
            ;

            iterator begin() const return iteratorthis, from;
            iterator end() const return iteratorthis, to;
            ;


            Or it could be T const* const pointing directly to that value, it is up to you.



            OT: Do not forget to make the internals private for both classes.






            share|improve this answer



























              17












              17








              17







              Here is my attempt, which does not hamper the semantics of iterators. The change is that now, each iterator knows its stopping value, to which it will set itself upon exceeding it. All end iterators of a range with equal to therefore compare equal.



              template <typename T> 
              struct range
              T from, to;
              range(T from, T to): from(from), to(to)

              struct iterator
              const T to; // iterator knows its bounds
              T current;

              T operator*() return current;

              iterator& operator++()
              ++current;
              if(current > to)
              // make it an end iterator
              // (current being exactly equal to 'current' of other end iterators)
              current = to;
              return *this;


              bool operator==(const iterator& other) const // OT: note the const
              return current == other.current;
              // OT: this is how we do !=
              bool operator!=(const iterator& other) const return !(*this == other);
              ;

              iterator begin() const return iteratorto, from;
              iterator end() const return iteratorto, to;
              ;


              Why is this better?



              The solution by @JeJo relies on the order in which you compare those iterators, i.e. it != end or end != it. But, in the case of range-based for, it is defined. Should you use this contraption in some other context, I advise the above approach.




              Alternatively, if sizeof(T) > sizeof(void*), it makes sense to store a pointer to the originating range instance (which in the case of the range-for persists until the end) and use that to refer to a single T value:



              template <typename T> 
              struct range
              T from, to;
              range(T from, T to): from(from), to(to)

              struct iterator
              const range* range;
              T current;

              iterator& operator++()
              ++current;
              if(current > range->to)
              current = range->to;
              return *this;


              ...
              ;

              iterator begin() const return iteratorthis, from;
              iterator end() const return iteratorthis, to;
              ;


              Or it could be T const* const pointing directly to that value, it is up to you.



              OT: Do not forget to make the internals private for both classes.






              share|improve this answer















              Here is my attempt, which does not hamper the semantics of iterators. The change is that now, each iterator knows its stopping value, to which it will set itself upon exceeding it. All end iterators of a range with equal to therefore compare equal.



              template <typename T> 
              struct range
              T from, to;
              range(T from, T to): from(from), to(to)

              struct iterator
              const T to; // iterator knows its bounds
              T current;

              T operator*() return current;

              iterator& operator++()
              ++current;
              if(current > to)
              // make it an end iterator
              // (current being exactly equal to 'current' of other end iterators)
              current = to;
              return *this;


              bool operator==(const iterator& other) const // OT: note the const
              return current == other.current;
              // OT: this is how we do !=
              bool operator!=(const iterator& other) const return !(*this == other);
              ;

              iterator begin() const return iteratorto, from;
              iterator end() const return iteratorto, to;
              ;


              Why is this better?



              The solution by @JeJo relies on the order in which you compare those iterators, i.e. it != end or end != it. But, in the case of range-based for, it is defined. Should you use this contraption in some other context, I advise the above approach.




              Alternatively, if sizeof(T) > sizeof(void*), it makes sense to store a pointer to the originating range instance (which in the case of the range-for persists until the end) and use that to refer to a single T value:



              template <typename T> 
              struct range
              T from, to;
              range(T from, T to): from(from), to(to)

              struct iterator
              const range* range;
              T current;

              iterator& operator++()
              ++current;
              if(current > range->to)
              current = range->to;
              return *this;


              ...
              ;

              iterator begin() const return iteratorthis, from;
              iterator end() const return iteratorthis, to;
              ;


              Or it could be T const* const pointing directly to that value, it is up to you.



              OT: Do not forget to make the internals private for both classes.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited May 21 at 7:20

























              answered May 20 at 9:19









              LogicStuffLogicStuff

              16.7k64061




              16.7k64061























                  13














                  Instead of a range object you could use a generator (a coroutine using co_yield). Despite it is not in the standard (but planned for C++20), some compilers already implement it.



                  See: https://en.cppreference.com/w/cpp/language/coroutines



                  With MSVC it would be:



                  #include <iostream>
                  #include <experimental/generator>

                  std::experimental::generator<double> rangeGenerator(double from, double to)
                  for (double x=from;x <= to;x++)

                  co_yield x;



                  int main()

                  for (auto i : rangeGenerator(5.1, 9.2))
                  std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1






                  share|improve this answer





























                    13














                    Instead of a range object you could use a generator (a coroutine using co_yield). Despite it is not in the standard (but planned for C++20), some compilers already implement it.



                    See: https://en.cppreference.com/w/cpp/language/coroutines



                    With MSVC it would be:



                    #include <iostream>
                    #include <experimental/generator>

                    std::experimental::generator<double> rangeGenerator(double from, double to)
                    for (double x=from;x <= to;x++)

                    co_yield x;



                    int main()

                    for (auto i : rangeGenerator(5.1, 9.2))
                    std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1






                    share|improve this answer



























                      13












                      13








                      13







                      Instead of a range object you could use a generator (a coroutine using co_yield). Despite it is not in the standard (but planned for C++20), some compilers already implement it.



                      See: https://en.cppreference.com/w/cpp/language/coroutines



                      With MSVC it would be:



                      #include <iostream>
                      #include <experimental/generator>

                      std::experimental::generator<double> rangeGenerator(double from, double to)
                      for (double x=from;x <= to;x++)

                      co_yield x;



                      int main()

                      for (auto i : rangeGenerator(5.1, 9.2))
                      std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1






                      share|improve this answer















                      Instead of a range object you could use a generator (a coroutine using co_yield). Despite it is not in the standard (but planned for C++20), some compilers already implement it.



                      See: https://en.cppreference.com/w/cpp/language/coroutines



                      With MSVC it would be:



                      #include <iostream>
                      #include <experimental/generator>

                      std::experimental::generator<double> rangeGenerator(double from, double to)
                      for (double x=from;x <= to;x++)

                      co_yield x;



                      int main()

                      for (auto i : rangeGenerator(5.1, 9.2))
                      std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited May 20 at 9:46

























                      answered May 20 at 9:15









                      P. PICARDP. PICARD

                      1869




                      1869





















                          8















                          Is there a simple way to create an iterable object that will behave
                          like a correct for loop on floats?




                          The simplest hack would be using the traits std::is_floating_point to provide different return (i.e. iter <= end) within the operator!= overload.



                          (See Live)



                          #include <type_traits>

                          bool operator!=(const iterator& other)

                          if constexpr (std::is_floating_point_v<T>) return current <= other.current;
                          return !(*this == other);



                          Warning: Even though that does the job, it breaks the meaning of operator!= overload.




                          Alternative Solution



                          The entire range class can be replaced by a simple function in which the values of the range will be populated with the help of std::iota
                          in the standard container std::vector.



                          Use SFINE, to restrict the use of the function for only the valid types.
                          This way, you can rely on standard implementations and forget about the reinventions.



                          (See Live)



                          #include <iostream>
                          #include <type_traits>
                          #include <vector> // std::vector
                          #include <numeric> // std::iota
                          #include <cstddef> // std::size_t
                          #include <cmath> // std::modf

                          // traits for valid template types(integers and floating points)
                          template<typename Type>
                          using is_integers_and_floats = std::conjunction<
                          std::is_arithmetic<Type>,
                          std::negation<std::is_same<Type, bool>>,
                          std::negation<std::is_same<Type, char>>,
                          std::negation<std::is_same<Type, char16_t>>,
                          std::negation<std::is_same<Type, char32_t>>,
                          std::negation<std::is_same<Type, wchar_t>>
                          /*, std::negation<std::is_same<char8_t, Type>> */ // since C++20
                          >;

                          template <typename T>
                          auto ragesof(const T begin, const T end)
                          -> std::enable_if_t<is_integers_and_floats<T>::value, std::vector<T>>

                          if (begin >= end) return std::vector<T>; // edge case to be considered
                          // find the number of elements between the range
                          const std::size_t size = [begin, end]() -> std::size_t

                          const std::size_t diffWhole
                          = static_cast<std::size_t>(end) - static_cast<std::size_t>(begin);
                          if constexpr (std::is_floating_point_v<T>)
                          double whole; // get the decimal parts of begin and end
                          const double decimalBegin = std::modf(static_cast<double>(begin), &whole);
                          const double decimalEnd = std::modf(static_cast<double>(end), &whole);
                          return decimalBegin <= decimalEnd ? diffWhole + 1 : diffWhole;

                          return diffWhole;
                          ();
                          // construct and initialize the `std::vector` with size
                          std::vector<T> vec(size);
                          // populates the range from [first, end)
                          std::iota(std::begin(vec), std::end(vec), begin);
                          return vec;


                          int main()

                          for (auto i : ragesof( 5, 9 ))
                          std::cout << i << ' '; // prints 5 6 7 8
                          std::cout << 'n';

                          for (auto i : ragesof(5.1, 9.2))
                          std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1






                          share|improve this answer





























                            8















                            Is there a simple way to create an iterable object that will behave
                            like a correct for loop on floats?




                            The simplest hack would be using the traits std::is_floating_point to provide different return (i.e. iter <= end) within the operator!= overload.



                            (See Live)



                            #include <type_traits>

                            bool operator!=(const iterator& other)

                            if constexpr (std::is_floating_point_v<T>) return current <= other.current;
                            return !(*this == other);



                            Warning: Even though that does the job, it breaks the meaning of operator!= overload.




                            Alternative Solution



                            The entire range class can be replaced by a simple function in which the values of the range will be populated with the help of std::iota
                            in the standard container std::vector.



                            Use SFINE, to restrict the use of the function for only the valid types.
                            This way, you can rely on standard implementations and forget about the reinventions.



                            (See Live)



                            #include <iostream>
                            #include <type_traits>
                            #include <vector> // std::vector
                            #include <numeric> // std::iota
                            #include <cstddef> // std::size_t
                            #include <cmath> // std::modf

                            // traits for valid template types(integers and floating points)
                            template<typename Type>
                            using is_integers_and_floats = std::conjunction<
                            std::is_arithmetic<Type>,
                            std::negation<std::is_same<Type, bool>>,
                            std::negation<std::is_same<Type, char>>,
                            std::negation<std::is_same<Type, char16_t>>,
                            std::negation<std::is_same<Type, char32_t>>,
                            std::negation<std::is_same<Type, wchar_t>>
                            /*, std::negation<std::is_same<char8_t, Type>> */ // since C++20
                            >;

                            template <typename T>
                            auto ragesof(const T begin, const T end)
                            -> std::enable_if_t<is_integers_and_floats<T>::value, std::vector<T>>

                            if (begin >= end) return std::vector<T>; // edge case to be considered
                            // find the number of elements between the range
                            const std::size_t size = [begin, end]() -> std::size_t

                            const std::size_t diffWhole
                            = static_cast<std::size_t>(end) - static_cast<std::size_t>(begin);
                            if constexpr (std::is_floating_point_v<T>)
                            double whole; // get the decimal parts of begin and end
                            const double decimalBegin = std::modf(static_cast<double>(begin), &whole);
                            const double decimalEnd = std::modf(static_cast<double>(end), &whole);
                            return decimalBegin <= decimalEnd ? diffWhole + 1 : diffWhole;

                            return diffWhole;
                            ();
                            // construct and initialize the `std::vector` with size
                            std::vector<T> vec(size);
                            // populates the range from [first, end)
                            std::iota(std::begin(vec), std::end(vec), begin);
                            return vec;


                            int main()

                            for (auto i : ragesof( 5, 9 ))
                            std::cout << i << ' '; // prints 5 6 7 8
                            std::cout << 'n';

                            for (auto i : ragesof(5.1, 9.2))
                            std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1






                            share|improve this answer



























                              8












                              8








                              8








                              Is there a simple way to create an iterable object that will behave
                              like a correct for loop on floats?




                              The simplest hack would be using the traits std::is_floating_point to provide different return (i.e. iter <= end) within the operator!= overload.



                              (See Live)



                              #include <type_traits>

                              bool operator!=(const iterator& other)

                              if constexpr (std::is_floating_point_v<T>) return current <= other.current;
                              return !(*this == other);



                              Warning: Even though that does the job, it breaks the meaning of operator!= overload.




                              Alternative Solution



                              The entire range class can be replaced by a simple function in which the values of the range will be populated with the help of std::iota
                              in the standard container std::vector.



                              Use SFINE, to restrict the use of the function for only the valid types.
                              This way, you can rely on standard implementations and forget about the reinventions.



                              (See Live)



                              #include <iostream>
                              #include <type_traits>
                              #include <vector> // std::vector
                              #include <numeric> // std::iota
                              #include <cstddef> // std::size_t
                              #include <cmath> // std::modf

                              // traits for valid template types(integers and floating points)
                              template<typename Type>
                              using is_integers_and_floats = std::conjunction<
                              std::is_arithmetic<Type>,
                              std::negation<std::is_same<Type, bool>>,
                              std::negation<std::is_same<Type, char>>,
                              std::negation<std::is_same<Type, char16_t>>,
                              std::negation<std::is_same<Type, char32_t>>,
                              std::negation<std::is_same<Type, wchar_t>>
                              /*, std::negation<std::is_same<char8_t, Type>> */ // since C++20
                              >;

                              template <typename T>
                              auto ragesof(const T begin, const T end)
                              -> std::enable_if_t<is_integers_and_floats<T>::value, std::vector<T>>

                              if (begin >= end) return std::vector<T>; // edge case to be considered
                              // find the number of elements between the range
                              const std::size_t size = [begin, end]() -> std::size_t

                              const std::size_t diffWhole
                              = static_cast<std::size_t>(end) - static_cast<std::size_t>(begin);
                              if constexpr (std::is_floating_point_v<T>)
                              double whole; // get the decimal parts of begin and end
                              const double decimalBegin = std::modf(static_cast<double>(begin), &whole);
                              const double decimalEnd = std::modf(static_cast<double>(end), &whole);
                              return decimalBegin <= decimalEnd ? diffWhole + 1 : diffWhole;

                              return diffWhole;
                              ();
                              // construct and initialize the `std::vector` with size
                              std::vector<T> vec(size);
                              // populates the range from [first, end)
                              std::iota(std::begin(vec), std::end(vec), begin);
                              return vec;


                              int main()

                              for (auto i : ragesof( 5, 9 ))
                              std::cout << i << ' '; // prints 5 6 7 8
                              std::cout << 'n';

                              for (auto i : ragesof(5.1, 9.2))
                              std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1






                              share|improve this answer
















                              Is there a simple way to create an iterable object that will behave
                              like a correct for loop on floats?




                              The simplest hack would be using the traits std::is_floating_point to provide different return (i.e. iter <= end) within the operator!= overload.



                              (See Live)



                              #include <type_traits>

                              bool operator!=(const iterator& other)

                              if constexpr (std::is_floating_point_v<T>) return current <= other.current;
                              return !(*this == other);



                              Warning: Even though that does the job, it breaks the meaning of operator!= overload.




                              Alternative Solution



                              The entire range class can be replaced by a simple function in which the values of the range will be populated with the help of std::iota
                              in the standard container std::vector.



                              Use SFINE, to restrict the use of the function for only the valid types.
                              This way, you can rely on standard implementations and forget about the reinventions.



                              (See Live)



                              #include <iostream>
                              #include <type_traits>
                              #include <vector> // std::vector
                              #include <numeric> // std::iota
                              #include <cstddef> // std::size_t
                              #include <cmath> // std::modf

                              // traits for valid template types(integers and floating points)
                              template<typename Type>
                              using is_integers_and_floats = std::conjunction<
                              std::is_arithmetic<Type>,
                              std::negation<std::is_same<Type, bool>>,
                              std::negation<std::is_same<Type, char>>,
                              std::negation<std::is_same<Type, char16_t>>,
                              std::negation<std::is_same<Type, char32_t>>,
                              std::negation<std::is_same<Type, wchar_t>>
                              /*, std::negation<std::is_same<char8_t, Type>> */ // since C++20
                              >;

                              template <typename T>
                              auto ragesof(const T begin, const T end)
                              -> std::enable_if_t<is_integers_and_floats<T>::value, std::vector<T>>

                              if (begin >= end) return std::vector<T>; // edge case to be considered
                              // find the number of elements between the range
                              const std::size_t size = [begin, end]() -> std::size_t

                              const std::size_t diffWhole
                              = static_cast<std::size_t>(end) - static_cast<std::size_t>(begin);
                              if constexpr (std::is_floating_point_v<T>)
                              double whole; // get the decimal parts of begin and end
                              const double decimalBegin = std::modf(static_cast<double>(begin), &whole);
                              const double decimalEnd = std::modf(static_cast<double>(end), &whole);
                              return decimalBegin <= decimalEnd ? diffWhole + 1 : diffWhole;

                              return diffWhole;
                              ();
                              // construct and initialize the `std::vector` with size
                              std::vector<T> vec(size);
                              // populates the range from [first, end)
                              std::iota(std::begin(vec), std::end(vec), begin);
                              return vec;


                              int main()

                              for (auto i : ragesof( 5, 9 ))
                              std::cout << i << ' '; // prints 5 6 7 8
                              std::cout << 'n';

                              for (auto i : ragesof(5.1, 9.2))
                              std::cout << i << ' '; // prints 5.1 6.1 7.1 8.1 9.1







                              share|improve this answer














                              share|improve this answer



                              share|improve this answer








                              edited May 21 at 8:32

























                              answered May 20 at 9:09









                              JeJoJeJo

                              5,75331028




                              5,75331028





















                                  5














                                  A floating-point loop or iterator should typically use integer types to hold the total number of iterations and the number of the current iteration, and then compute the "loop index" value used within the loop based upon those and loop-invariant floating-point values.



                                  For example:



                                  for (int i=-10; i<=10; i++)

                                  double x = i/10.0; // Substituting i*0.1 would be faster but less accurate



                                  or



                                  for (int i=0; i<=16; i++)

                                  double x = ((startValue*(16-i))+(endValue*i))*(1/16);



                                  Note that there is no possibility of rounding errors affecting the number of iterations. The latter calculation is guaranteed to yield a correctly-rounded result at the endpoints; computing startValue+i*(endValue-startValue) would likely be faster (since the loop-invariant (endValue-startValue) can be hoisted) but may be less accurate.



                                  Using an integer iterator along with a function to convert an integer to a floating-point value is probably the most robust way to iterate over a range of floating-point values. Trying to iterate over floating-point values directly is far more likely to yield "off-by-one" errors.






                                  share|improve this answer



























                                    5














                                    A floating-point loop or iterator should typically use integer types to hold the total number of iterations and the number of the current iteration, and then compute the "loop index" value used within the loop based upon those and loop-invariant floating-point values.



                                    For example:



                                    for (int i=-10; i<=10; i++)

                                    double x = i/10.0; // Substituting i*0.1 would be faster but less accurate



                                    or



                                    for (int i=0; i<=16; i++)

                                    double x = ((startValue*(16-i))+(endValue*i))*(1/16);



                                    Note that there is no possibility of rounding errors affecting the number of iterations. The latter calculation is guaranteed to yield a correctly-rounded result at the endpoints; computing startValue+i*(endValue-startValue) would likely be faster (since the loop-invariant (endValue-startValue) can be hoisted) but may be less accurate.



                                    Using an integer iterator along with a function to convert an integer to a floating-point value is probably the most robust way to iterate over a range of floating-point values. Trying to iterate over floating-point values directly is far more likely to yield "off-by-one" errors.






                                    share|improve this answer

























                                      5












                                      5








                                      5







                                      A floating-point loop or iterator should typically use integer types to hold the total number of iterations and the number of the current iteration, and then compute the "loop index" value used within the loop based upon those and loop-invariant floating-point values.



                                      For example:



                                      for (int i=-10; i<=10; i++)

                                      double x = i/10.0; // Substituting i*0.1 would be faster but less accurate



                                      or



                                      for (int i=0; i<=16; i++)

                                      double x = ((startValue*(16-i))+(endValue*i))*(1/16);



                                      Note that there is no possibility of rounding errors affecting the number of iterations. The latter calculation is guaranteed to yield a correctly-rounded result at the endpoints; computing startValue+i*(endValue-startValue) would likely be faster (since the loop-invariant (endValue-startValue) can be hoisted) but may be less accurate.



                                      Using an integer iterator along with a function to convert an integer to a floating-point value is probably the most robust way to iterate over a range of floating-point values. Trying to iterate over floating-point values directly is far more likely to yield "off-by-one" errors.






                                      share|improve this answer













                                      A floating-point loop or iterator should typically use integer types to hold the total number of iterations and the number of the current iteration, and then compute the "loop index" value used within the loop based upon those and loop-invariant floating-point values.



                                      For example:



                                      for (int i=-10; i<=10; i++)

                                      double x = i/10.0; // Substituting i*0.1 would be faster but less accurate



                                      or



                                      for (int i=0; i<=16; i++)

                                      double x = ((startValue*(16-i))+(endValue*i))*(1/16);



                                      Note that there is no possibility of rounding errors affecting the number of iterations. The latter calculation is guaranteed to yield a correctly-rounded result at the endpoints; computing startValue+i*(endValue-startValue) would likely be faster (since the loop-invariant (endValue-startValue) can be hoisted) but may be less accurate.



                                      Using an integer iterator along with a function to convert an integer to a floating-point value is probably the most robust way to iterate over a range of floating-point values. Trying to iterate over floating-point values directly is far more likely to yield "off-by-one" errors.







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered May 20 at 18:25









                                      supercatsupercat

                                      58.6k4118158




                                      58.6k4118158



























                                          draft saved

                                          draft discarded
















































                                          Thanks for contributing an answer to Stack Overflow!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid


                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.

                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function ()
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56217541%2fhow-to-create-a-range-like-iterable-object-of-floats%23new-answer', 'question_page');

                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          Popular posts from this blog

                                          Wikipedia:Vital articles Мазмуну Biography - Өмүр баян Philosophy and psychology - Философия жана психология Religion - Дин Social sciences - Коомдук илимдер Language and literature - Тил жана адабият Science - Илим Technology - Технология Arts and recreation - Искусство жана эс алуу History and geography - Тарых жана география Навигация менюсу

                                          Bruxelas-Capital Índice Historia | Composición | Situación lingüística | Clima | Cidades irmandadas | Notas | Véxase tamén | Menú de navegacióneO uso das linguas en Bruxelas e a situación do neerlandés"Rexión de Bruxelas Capital"o orixinalSitio da rexiónPáxina de Bruselas no sitio da Oficina de Promoción Turística de Valonia e BruxelasMapa Interactivo da Rexión de Bruxelas-CapitaleeWorldCat332144929079854441105155190212ID28008674080552-90000 0001 0666 3698n94104302ID540940339365017018237

                                          What should I write in an apology letter, since I have decided not to join a company after accepting an offer letterShould I keep looking after accepting a job offer?What should I do when I've been verbally told I would get an offer letter, but still haven't gotten one after 4 weeks?Do I accept an offer from a company that I am not likely to join?New job hasn't confirmed starting date and I want to give current employer as much notice as possibleHow should I address my manager in my resignation letter?HR delayed background verification, now jobless as resignedNo email communication after accepting a formal written offer. How should I phrase the call?What should I do if after receiving a verbal offer letter I am informed that my written job offer is put on hold due to some internal issues?Should I inform the current employer that I am about to resign within 1-2 weeks since I have signed the offer letter and waiting for visa?What company will do, if I send their offer letter to another company