Unsigned int reverse iteration with for loops

我们两清 提交于 2019-12-17 17:33:39

问题


I want the iterator variable in a for loop to reverse iterate to 0 as an unsigned int, and I cannot think of a similar comparison to i > -1, as you would do if it was a signed int.

for (unsigned int i = 10; i <= 10; --i) { ... }

But this seems very unclear, as it is relying on the numerical overflow of the unsigned integer to be above 10.

Maybe I just don't have a clear head, but whats a better way to do this...

Disclaimer: this is just a simple use case, the upper limit of 10 is trivial, it could be anything, and i must be an unsigned int.


回答1:


You can use

for (unsigned int j = n; j-- > 0; ) {}

It iterates from n-1 down to 0.




回答2:


The following does what you want:

for (unsigned i = 10; i != static_cast<unsigned>(-1); --i)
{
    // ...
}

This is perfectly defined and actually works. Arithmetic on signed types is accurately defined by the standard. Indeed:

From 4.7/2 (regarding casting to an unsigned type):

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type)

and 3.9.1/4

Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2^n where n is the number of bits in the value representation of that particular size of integer




回答3:


My pattern for this is usually...

for( unsigned int i_plus_one = n; i_plus_one > 0; --i_plus_one )
{
    const unsigned int i = i_plus_one - 1;
    // ...
}



回答4:


Are you really iterating down from some number greater than std::numeric_limits<int>::max()? If not, I would actually suggest just using a normal int as your loop variable and static_cast it to unsigned in the places in your code that expect it to be unsigned. This way you can use the intuitive >= 0 or > -1 condition and in general I would expect it to be more readable than any of the unsigned alternatives.

The static_cast would just be to tell the compiler how to operate on the variable and have no performance implications at all.




回答5:


I can think the two options are either cast or singed numbers (can be done implicitly be comparing to -1, for example) or use the loop condition to check for overflow like this:

for(unsigned i=10;i>i-1;--i){ } // i = 10, 9, ... , 1
for(unsigned i=10;i+1>i;--i){ } // i = 10, 9, ... , 1,0

This loop will continue until i overflows (meaning that it reached zero). Note that is important that i iterates by 1, or you might end-up with an infinite loop.




回答6:


I would use two variables:

unsigned int start = 10;
for (unsigned int j = 0, i = start; j <= start; ++ j, -- i) {
    // ...
}

You can also use a while loop:

unsigned int start = 10;
unsigned int i = start + 1;
while (i --) {
    // ...
}



回答7:


for(unsigned i = x ; i != 0 ; i--){ ...

And if you want to execute the loop body when i == 0 and stop after that. Just start with i = x+1;

BTW, why i must be unsigned ?




回答8:


You can try and define the following macro:

#define for_range(_type, _param, _A1, _B1) \
    for (_type _param = _A1, _finish = _B1,\
    _step = static_cast<_type>(2*(((int)_finish)>(int)_param)-1),\
    _stop = static_cast<_type>(((int)_finish)+(int)_step); _param != _stop; \
_param = static_cast<_type>(((int)_param)+(int)_step))

Now you can use it:

for_range (unsigned, i, 10,0)
{
    cout << "backwards i: " << i << endl;
}

It can be used to iterate backwards and forwards through unsigned, integers, enums and chars:

for_range (char, c, 'z','a')
{
    cout << c << endl;
}

enum Count { zero, one, two, three }; 

for_range (Count, c, zero, three)
{
    cout << "forward: " << c << endl;
}

Despite its awkward definition it is optimized very well. I looked at disassembler in VC++. The code is extremely efficient. Don't be put off but the three for statements: the compiler will produce only one loop after optimization! You can even define enclosed loops:

unsigned p[4][5];

for_range (Count, i, zero,three)
    for_range(unsigned int, j, 4, 0)
    {   
        p[i][j] = static_cast<unsigned>(i)+j;
    }

You obviously cannot iterate through enumerated types with gaps.




回答9:


I am new to c++, my answer might be realy stupid but, i do this for this kind of reverse loops;

size_t count = 3;
size_t newCount = 0;
if (count > 0)
    for (size_t i = count - 1; i >= newCount; i--)
    {
        //do your work here

        //and at the end
        if (i == 0)
            break;
    }

and it works. since "i--" part at the loop executed at the next step, break should work allright. what do you think is this way safe ?




回答10:


Avoiding underflow

unsigned int i = n;
while (i !=0){
--i;
...
}



回答11:


Here is a simple trick to ovoid overflow if i iterates by 1:

for(unsigned int i = n-1; i+1 >= 1; i--) {;}

If you want i to iterate for more than 1:

unsigned int d = 2;
for(unsigned int i = n-1; i+d >= d; i-=d) {;}



回答12:


Just:

int start = 10;
for(unsigned int iPlus1 = start + 1 ; iPlus1 > 0 ; iPlus1--) {
  // use iPlus1 - 1 if you need (say) an array index
  a[iPlus1 - 1] = 123; // ...
}

No?




回答13:


One more way:

for(unsigned i = n-1; i < n ; --i) 
{       
    // Iterates from n-1 to 0
}

Simillarly for size_t (unsigned integer type) use the same trick

for(std::size_t i = n-1; i < n ; --i) 
{       
    // Iterates from n-1 to 0
}


来源:https://stackoverflow.com/questions/5458204/unsigned-int-reverse-iteration-with-for-loops

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!