Jump to content
  • Advertisement
Sign in to follow this  
Bromordra

Odd C++ anamoly

This topic is 3089 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I was fiddling around with C++ today when I executed this particular program.

#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.

Share this post


Link to post
Share on other sites
Advertisement
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?

Share this post


Link to post
Share on other sites
Looking at the ASM output, the culprit is likely:

mov eax, DWORD PTR _x$[ebp]
shl eax, 1


After so many shifts, it's just shifting 0's into other 0's.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!