#include <iostream>
using namespace std;
int main()
{
for(int x = 1;;x*=2)
{
cout << x << endl;
}
}
I expected this to return an endless stream of numbers, multiplying by 2 with every increment (2,4,8,16,32,ect...). Instead, it returned and endless stream of 0s. Can anyone tell me why this happened? I am way past simple programs like these in my learning of C++, but I was just fiddling around when I discovered this. It really does stump me what's making it do that.
Odd C++ anamoly
Hi, I was fiddling around with C++ today when I executed this particular program.
Quote:I expected this to return an endless stream of numbers, multiplying by 2 with every increment (2,4,8,16,32,ect...).It did.
Quote:Instead, it returned and endless stream of 0s.Yep, it did that too.
unsigned char i = 128;cout << i << endl;i *= 2;cout << i << endl; // what is printed here? Why?
Looking at the ASM output, the culprit is likely:
After so many shifts, it's just shifting 0's into other 0's.
mov eax, DWORD PTR _x$[ebp]shl eax, 1
After so many shifts, it's just shifting 0's into other 0's.
Never mind, I figured it out. I feel kinda dumb now. I went and stepped through the program from the beginning, and lo and behold, there's my sequence of numbers multiplying by two, after a certain point, the number went to one negative number, than all zeroes. I'm guessing that is because the number rolled-over because it got too big for the int to hold. Cool. Thanks for your help.
It's not that it gets too big to hold; if you used 3 instead of 2, it'd overflow and you'd get a repeating sequence and no 0's.
Bit shifting left by 1 position is a quick way of multiplying by 2. Obviously after so many shifts, all the binary 1's in the number are gone so it ends up as 0 (the reason it goes negative on the last number is because of the sign change).
Bit shifting left by 1 position is a quick way of multiplying by 2. Obviously after so many shifts, all the binary 1's in the number are gone so it ends up as 0 (the reason it goes negative on the last number is because of the sign change).
Ah, thanks Gunnie, that makes sense actually. I'm glad I learned something today. So you said that if i used 3 I'd get a repeating sequence? I guess there isn't any way to get numbers that go up to infinity, is there? Not that I'd ever actually need or want them.
It'd depend on what you're expecting from "infinity". If you mean a number of infinite length... you'd have to go beyond the 32-bit integer system, I believe.
Are you yet learned in the ways of how integers/etc work on a binary level?
Are you yet learned in the ways of how integers/etc work on a binary level?
If you are not really into Math, the following might make no sense. I'm just posting it in case someone finds it interesting.
In the integer numbers, consider the equivalence relationship where a~b iff a-b is a multiple of 2^32. Now consider the equivalence classes. You'll have the class of all the multiples of 2^32, the class of numbers that can be written as a multiple of 2^32 plus 1, the class of numbers that can be written as a multiple of 2^32 plus 2, etc. There are 2^32 classes. Notice that a multiple of 2^32 + i plus a multiple of 2^32 + j is a multiple of 2^32 + (i+j). This allows us to define addition of classes. Similarly you can define multiplication of classes. These operations provide the set of classes with the structure of a commutative ring.
Probably what an `int' represents in your compiler is one of those classes. In the case of `unsigned int', we represent each class with a number in the range [0,2^32). In the case of `signed int', the representatives are chosen in the range [-2^31,2^31) (not guaranteed by the standard, but I bet that's what signed ints are in your platform).
This group is often called the group of integers modulo 2^32, and it can be written as Z/(2^32).
Now, if you start multiplying a number by 2 repeatedly, you'll end up with a multiple of 2^32, which is 0 in Z/(2^32).
In the integer numbers, consider the equivalence relationship where a~b iff a-b is a multiple of 2^32. Now consider the equivalence classes. You'll have the class of all the multiples of 2^32, the class of numbers that can be written as a multiple of 2^32 plus 1, the class of numbers that can be written as a multiple of 2^32 plus 2, etc. There are 2^32 classes. Notice that a multiple of 2^32 + i plus a multiple of 2^32 + j is a multiple of 2^32 + (i+j). This allows us to define addition of classes. Similarly you can define multiplication of classes. These operations provide the set of classes with the structure of a commutative ring.
Probably what an `int' represents in your compiler is one of those classes. In the case of `unsigned int', we represent each class with a number in the range [0,2^32). In the case of `signed int', the representatives are chosen in the range [-2^31,2^31) (not guaranteed by the standard, but I bet that's what signed ints are in your platform).
This group is often called the group of integers modulo 2^32, and it can be written as Z/(2^32).
Now, if you start multiplying a number by 2 repeatedly, you'll end up with a multiple of 2^32, which is 0 in Z/(2^32).
I'm not sure about what alvaro says. I could've missed something, but are you maybe implying that you get 0 because there's no number in the "set/group/class" outside of that range?
I did replace the "shl eax, 1" with "imul eax, 2" and got the same result as with the shift, but this could be due to an internal processor optimization (you know how they are).
It might be differences in the way floating points are handled or the way the FPU crunches numbers, but doing the same thing with x as a float and multiplying by 2 produces a pattern in the same way as multiplying x as an int by 3 or 5 or any other non-shift-friendly number.
Can anyone else weigh in on this one?
I did replace the "shl eax, 1" with "imul eax, 2" and got the same result as with the shift, but this could be due to an internal processor optimization (you know how they are).
It might be differences in the way floating points are handled or the way the FPU crunches numbers, but doing the same thing with x as a float and multiplying by 2 produces a pattern in the same way as multiplying x as an int by 3 or 5 or any other non-shift-friendly number.
Can anyone else weigh in on this one?
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement