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?

How to teach an undergraduate course without having taken that course formally before?

Possibility of faking someone's public key

What did the 'turbo' button actually do?

switching alignment

How to deceive the MC

Was this scene in S8E06 added because of fan reactions to S8E04?

Count all vowels in string

Split into three!

Why was this character made Grand Maester?

Why did OJ Simpson's trial take 9 months?

Why did other houses not demand this?

Piping the output of comand columns

Flatten not working

Is this homebrew "Cactus Grenade" cantrip balanced?

Did significant numbers of Japanese officers escape prosecution during the Tokyo Trials?

Merge pdfs sequentially

Why do the i8080 I/O instructions take a byte-sized operand to determine the port?

To exponential digit growth and beyond!

Ribbon Cable Cross Talk - Is there a fix after the fact?

Why do testers need root cause analysis?

Storing voxels for a voxel Engine in C++

How does Dreadhorde Arcanist interact with split cards?

Knight's Tour on a 7x7 Board starting from D5

How to remove new line added by readarray when using a delimiter?



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;








15















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
    12 hours ago






  • 7





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

    – Daniel Langr
    12 hours ago











  • 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
    12 hours ago












  • @Someprogrammerdude I did not know about this library - thanks!

    – Erel Segal-Halevi
    6 hours ago






  • 5





    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
    3 hours ago


















15















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
    12 hours ago






  • 7





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

    – Daniel Langr
    12 hours ago











  • 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
    12 hours ago












  • @Someprogrammerdude I did not know about this library - thanks!

    – Erel Segal-Halevi
    6 hours ago






  • 5





    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
    3 hours ago














15












15








15








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 2 hours ago









JeJo

5,49831027




5,49831027










asked 12 hours ago









Erel Segal-HaleviErel Segal-Halevi

12.6k2371120




12.6k2371120












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

    – Some programmer dude
    12 hours ago






  • 7





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

    – Daniel Langr
    12 hours ago











  • 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
    12 hours ago












  • @Someprogrammerdude I did not know about this library - thanks!

    – Erel Segal-Halevi
    6 hours ago






  • 5





    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
    3 hours ago


















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

    – Some programmer dude
    12 hours ago






  • 7





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

    – Daniel Langr
    12 hours ago











  • 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
    12 hours ago












  • @Someprogrammerdude I did not know about this library - thanks!

    – Erel Segal-Halevi
    6 hours ago






  • 5





    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
    3 hours ago

















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

– Some programmer dude
12 hours ago





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

– Some programmer dude
12 hours ago




7




7





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

– Daniel Langr
12 hours ago





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

– Daniel Langr
12 hours ago













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
12 hours ago






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
12 hours ago














@Someprogrammerdude I did not know about this library - thanks!

– Erel Segal-Halevi
6 hours ago





@Someprogrammerdude I did not know about this library - thanks!

– Erel Segal-Halevi
6 hours ago




5




5





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
3 hours ago






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
3 hours ago













4 Answers
4






active

oldest

votes


















14














Here is my attempt, which I think 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. Two end iterators of a range with equal to therefore compare equal, stopping the iteration.



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)
return current == other.current;

bool operator!=(const iterator& other)
return !(*this == other); // this is how we do !=

;
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;
T operator*()
return current;

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

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

bool operator!=(const iterator& other)
return !(*this == other); // this is how we do !=

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


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






share|improve this answer




















  • 2





    If the comparison of iterators makes sense only for the same range (which makes sense to me), then to equals other.to and the second part of the condition (after OR) is superfluous.

    – Daniel Langr
    12 hours ago












  • @DanielLangr The second part is the essence of my solution. I am not comparing two tos. I will try to make this more clear.

    – LogicStuff
    12 hours ago






  • 2





    You make this: current == to && other.current == other.to. My point was that if to == other.to (same range), then current == other.current, which exactly is the first part of the whole condition.

    – Daniel Langr
    12 hours ago












  • Ahh, I get it, thanks.

    – LogicStuff
    12 hours ago


















10














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.






    share|improve this answer
































      1














      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









        14














        Here is my attempt, which I think 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. Two end iterators of a range with equal to therefore compare equal, stopping the iteration.



        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)
        return current == other.current;

        bool operator!=(const iterator& other)
        return !(*this == other); // this is how we do !=

        ;
        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;
        T operator*()
        return current;

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

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

        bool operator!=(const iterator& other)
        return !(*this == other); // this is how we do !=

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


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






        share|improve this answer




















        • 2





          If the comparison of iterators makes sense only for the same range (which makes sense to me), then to equals other.to and the second part of the condition (after OR) is superfluous.

          – Daniel Langr
          12 hours ago












        • @DanielLangr The second part is the essence of my solution. I am not comparing two tos. I will try to make this more clear.

          – LogicStuff
          12 hours ago






        • 2





          You make this: current == to && other.current == other.to. My point was that if to == other.to (same range), then current == other.current, which exactly is the first part of the whole condition.

          – Daniel Langr
          12 hours ago












        • Ahh, I get it, thanks.

          – LogicStuff
          12 hours ago















        14














        Here is my attempt, which I think 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. Two end iterators of a range with equal to therefore compare equal, stopping the iteration.



        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)
        return current == other.current;

        bool operator!=(const iterator& other)
        return !(*this == other); // this is how we do !=

        ;
        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;
        T operator*()
        return current;

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

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

        bool operator!=(const iterator& other)
        return !(*this == other); // this is how we do !=

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


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






        share|improve this answer




















        • 2





          If the comparison of iterators makes sense only for the same range (which makes sense to me), then to equals other.to and the second part of the condition (after OR) is superfluous.

          – Daniel Langr
          12 hours ago












        • @DanielLangr The second part is the essence of my solution. I am not comparing two tos. I will try to make this more clear.

          – LogicStuff
          12 hours ago






        • 2





          You make this: current == to && other.current == other.to. My point was that if to == other.to (same range), then current == other.current, which exactly is the first part of the whole condition.

          – Daniel Langr
          12 hours ago












        • Ahh, I get it, thanks.

          – LogicStuff
          12 hours ago













        14












        14








        14







        Here is my attempt, which I think 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. Two end iterators of a range with equal to therefore compare equal, stopping the iteration.



        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)
        return current == other.current;

        bool operator!=(const iterator& other)
        return !(*this == other); // this is how we do !=

        ;
        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;
        T operator*()
        return current;

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

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

        bool operator!=(const iterator& other)
        return !(*this == other); // this is how we do !=

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


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






        share|improve this answer















        Here is my attempt, which I think 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. Two end iterators of a range with equal to therefore compare equal, stopping the iteration.



        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)
        return current == other.current;

        bool operator!=(const iterator& other)
        return !(*this == other); // this is how we do !=

        ;
        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;
        T operator*()
        return current;

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

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

        bool operator!=(const iterator& other)
        return !(*this == other); // this is how we do !=

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


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







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 6 hours ago

























        answered 12 hours ago









        LogicStuffLogicStuff

        16.5k64061




        16.5k64061







        • 2





          If the comparison of iterators makes sense only for the same range (which makes sense to me), then to equals other.to and the second part of the condition (after OR) is superfluous.

          – Daniel Langr
          12 hours ago












        • @DanielLangr The second part is the essence of my solution. I am not comparing two tos. I will try to make this more clear.

          – LogicStuff
          12 hours ago






        • 2





          You make this: current == to && other.current == other.to. My point was that if to == other.to (same range), then current == other.current, which exactly is the first part of the whole condition.

          – Daniel Langr
          12 hours ago












        • Ahh, I get it, thanks.

          – LogicStuff
          12 hours ago












        • 2





          If the comparison of iterators makes sense only for the same range (which makes sense to me), then to equals other.to and the second part of the condition (after OR) is superfluous.

          – Daniel Langr
          12 hours ago












        • @DanielLangr The second part is the essence of my solution. I am not comparing two tos. I will try to make this more clear.

          – LogicStuff
          12 hours ago






        • 2





          You make this: current == to && other.current == other.to. My point was that if to == other.to (same range), then current == other.current, which exactly is the first part of the whole condition.

          – Daniel Langr
          12 hours ago












        • Ahh, I get it, thanks.

          – LogicStuff
          12 hours ago







        2




        2





        If the comparison of iterators makes sense only for the same range (which makes sense to me), then to equals other.to and the second part of the condition (after OR) is superfluous.

        – Daniel Langr
        12 hours ago






        If the comparison of iterators makes sense only for the same range (which makes sense to me), then to equals other.to and the second part of the condition (after OR) is superfluous.

        – Daniel Langr
        12 hours ago














        @DanielLangr The second part is the essence of my solution. I am not comparing two tos. I will try to make this more clear.

        – LogicStuff
        12 hours ago





        @DanielLangr The second part is the essence of my solution. I am not comparing two tos. I will try to make this more clear.

        – LogicStuff
        12 hours ago




        2




        2





        You make this: current == to && other.current == other.to. My point was that if to == other.to (same range), then current == other.current, which exactly is the first part of the whole condition.

        – Daniel Langr
        12 hours ago






        You make this: current == to && other.current == other.to. My point was that if to == other.to (same range), then current == other.current, which exactly is the first part of the whole condition.

        – Daniel Langr
        12 hours ago














        Ahh, I get it, thanks.

        – LogicStuff
        12 hours ago





        Ahh, I get it, thanks.

        – LogicStuff
        12 hours ago













        10














        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





























          10














          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



























            10












            10








            10







            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 11 hours ago

























            answered 12 hours ago









            P. PICARDP. PICARD

            1468




            1468





















                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.






                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.






                  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.






                    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.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited 6 hours ago

























                    answered 12 hours ago









                    JeJoJeJo

                    5,49831027




                    5,49831027





















                        1














                        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



























                          1














                          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

























                            1












                            1








                            1







                            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 3 hours ago









                            supercatsupercat

                            58.4k4117156




                            58.4k4117156



























                                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

                                Siegen Nawigatsjuun

                                Log på Navigationsmenu

                                Log på Navigationsmenu