Click here to Skip to main content
15,891,777 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
In SQL, you execute:
SQL
DECLARE @i int=1024*1024*1024
SET @i = @i + @i

you get:
SQL
Msg 8115, Level 16, State 2, Line 2
Arithmetic overflow error converting expression to data type int.


SET @i = @i - 1 + @i
works just fine, @i becomes 2147483647. If you insert a minus (-) just after "int=" in the original, it works fine, and @i=-2147483648. I'm not complaining about that, mind you, I learned the overflow message was your friend over 30 years ago. When I learned FORTRAN 30+ years ago, it did that. I thought every programming language I used would do that. Since I made sure I didn't code an error like that, I just thought I was protected by the arithmetic overflow error.

Enter a C# application I wrote, where I wanted to test it's limits. I got it to blow up with a Stack overflow trace error. I was running in debug mode, so I reviewed the numbers. What the??? One of the int counters I was using was close to minus 2 billion. I'm only adding positive numbers, how can that happen??? I find out the compiled version doesn't blow up with a Stack Overflow and the int counter is a bit lower still. I start upping the anti, increasing the load and each time, it works, the counter gets a smaller and smaller negative number. Just before it blows the counter gets down to around -40K records. Changing the counter from int to uint the counter is just shy of the 4G maximum value by about 40K records.

I think that's a bug. Did I find a bug in C#?

By the way, later I doubled values starting from 1 and 1073741824 multiplied by 2 is -2147483648. Maybe I should have doubled that to see if I got 0?

PS I put in a try/catch block and the stack overflow won't catch. That makes sense to me (It is disappointing) and I don't think that is a bug.
Posted

KP Lee wrote:
One of the int counters I was using was close to minus 2 billion. I'm only adding positive numbers, how can that happen???


OK, this one is enough. Sorry for your 30 years of experience: perhaps you learned some FORTRAN (I used it, too, in the very beginning, before I realized it does not worth the effort), but you did not get to understanding some of very basic fundamentals of computing. Of course, adding to the integer number must end up having a negative number.

What you are talking about have nothing to do with stack overflow. If you want to know how stack and stack overflow works, it should be a separate question. This is integer overflow.

Of course you did not find a bug in C#, but you did find one in your understanding. Not a big deal: just fix it. You will find complete and comprehensive explanation here:

http://en.wikipedia.org/wiki/Two%27s_complement.

The thing is: you are using a system where signed integers are interpreted using two's complement representation. This representation is very practical: it allows for CPU to perform arithmetic operations using no information about a type of integer number, signed or unsigned or operands of different types. Also, it exclude the presence of -0 and +0 as different objects.

For more background on the topic, please see:
http://en.wikipedia.org/wiki/Signed_number_representations as well as Web links found in this article.

[EDIT]

To get calculation sensitive to integer overflow do them under checked mode:
C#
checked {
    int myInt = 1 << 30; //positive 2^30, 2^31 is already negative as 1 << 31 is a sign bit

    //attempt to get 1 << 32 == 0x80000000 will overflow to -2147483648
    myInt = myInt * 2; //but exception will be thrown here only under "checked"
}    


Maximum 32-bit int is (int)0x7fffffff, isn't that obvious?

[END EDIT]

Good luck,
—SA
 
Share this answer
 
v5
Comments
KP Lee 21-Oct-11 2:26am    
Yes I know 2's complement, I've had extensive training on both 2's and 1's complement systems because at the time 1's complement systems existed. It's easy to verify it's 2's comp by the fact that with a signed 32 bit number you can create a number equal to negative 2 to the 31'st power. The KEY word here is SIGNED!!! It is critical that the system you use UNDERSTANDS it's signed. SQL understands it is SIGNED and will not LET you get an invalid mathematical result. This is what I was trained in, so many years ago. When you reach positive 2^31-1 on a 32 bit number there is one "0" followed by 31 1's. On an unsigned int adding one, there's no problem because the result is 1 followed by 31 0's. Adding two positive numbers should NEVER result in a negative number because that is an INVALID MATHEMATICAL RESULT!!! Adding 1 in SQL at this point to a 32 bit signed integer results in an ARITHMETIC overflow error, not a Stack overflow (Yes, that was a different issue, sorry for overloading your brain by talking about 2 separate issues in the same note.)
Yes, 1 followed by 31 zeros is -2^31. Adding 1 to positive (2^31 - 1) to positive 1 shouldn't produce negative 2^31 power.
Sergey Alexandrovich Kryukov 21-Oct-11 15:32pm    
Please see my update. Look, after all, sit with pen and paper (+ VS Debugger) and find all those values, instead of referencing your training.

Sorry, nobody cares about your training, only what you understand and what you can do is important. Look, my experience also getting close to 30 years, but I don't push it forward when some boy points out my mistake, but I try to improve myself instead.

Now, about mathematics, do you understand that computer system does not represent the mathematical notion of "natural number", "integer number", "real number" as all those entities are infinite? So, if you want to operate mathematical rules, apply them to different mathematical objects such as "signed 32-bit number" which only represents some sub-set of the set of "integer numbers". Can you see the methodical problem of your argument?

What you need is probably using checked, but in many cases wrapping a number around the maximum/minimum is the best. This is not violation of mathematics, this is violation of your vision of mathematics, which is wider subject than you can see.

--SA
KP Lee 21-Oct-11 23:29pm    
I'm willing to learn. I ASKED if it was a bug. If you had said something about "checked" to begin with, I'd have realized that the lazy math was intentional and not a bug at all. This is a complex language, it isn't possible to know everything to begin with. "Help" is certainly NOT a mind-reader and I'm not a mind-reader knowing what keyword to use to find the information I am interested in. Even searching the checked keyword in the index required browsing to find the compiler level version: "/checked[+ | -]" vs. scoped checked/unchecked commands. (Lazy programming is not implementing something for performance reasons, but allowing the program to do what it is supposed to in special cases like applying.)

Yes, I know the hex value of the max int value. It exactly matches the binary value which is 2^31-1. Or 1 zero followed by 31 1's. I don't bother memorizing it, didn't know bit shifting was implemented. I did bother to memorize 2^10 which is 1024 decimal. On a system that checks values, 1024*1024*1024 - 1 + 1024*1024*1024 is the easiest way for me to remember how to mathematically get there. (The Maxvalue property is handy for that.)
Sergey Alexandrovich Kryukov 21-Oct-11 23:44pm    
OK, great, issues are sorted out.
Sorry I did not write about "checked" in first place -- it happens sometimes, as the brain is not oriented in that direction, while trying to confront the idea of false "invalid mathematical result", not to answer (unwritten) question "how to make it the way I expect".
Good luck,
--SA
Not sure on SQL side; but C# works fine as per its standards.

Since, you are a senior programmer, let me give a brief view on the C# int data type.

Every value type is an object derived from System.Object<-System.Value. When you declare 'int' in C#, it's a macro representing System.Int32 type.

Int32 is an immutable value type that represents signed integers with values that range from negative 2,147,483,648 (which is represented by the Int32.MinValue constant) through positive 2,147,483,647 (which is represented by the Int32.MaxValue constant). .NET Framework also supports an unsigned 32-bit integer value type, UInt32, which represents values that range from 0 to 4,294,967,295.

As per arithmetic overflow, the internally stored bits are jammed around!
 
Share this answer
 
v3
Comments
KP Lee 21-Oct-11 2:30am    
It's standards says it is OK to produce invalid mathimatical results? Where is that written?
lukeer 21-Oct-11 2:59am    
FORTRAN, AFAIR, is targeted at mathematical calculations.
C# is a general purpose language. So for mathematical purposes this exact behaviour may be suboptimal. But it's the intended behaviour for other purposes, it's part of the 'C' language heritage and therefore a commonly accepted compromise.
Sergey Alexandrovich Kryukov 21-Oct-11 15:37pm    
A practical resolution is using checked mode, as I just added to my answer.
As to mathematics, both set of rules are valid. Arithmetic of "integer number" (as it is understood in school algebra is actually an infinite-size object) is different from arithmetic of "32-bit signed integer" but it does not make any of them invalid. Mathematics works with any thinkable objects, but axioms (for example, algebra) is different for objects of different nature, that's it.
--SA
lukeer 21-Oct-11 2:51am    
Edited for readability and spelling.
the int is signed type, so you've added enough to set the MSB, and flag it as a -ve number

I think your stack fault may be a red herring
 
Share this answer
 
Comments
KP Lee 21-Oct-11 2:46am    
The stack fault was a separate issue. Not a red herring, but confusing combined with the numeric problem. So adding two positive numbers together SHOULD produce a negative result? Where is that written? It violates every standard I've ever encountered. I used SQL to illistrate a system that DOES follow the mathematical standards set years ago to NOT allow invalid mathematical results.

I intentionally set up a recursive call to be called so many times the system couldn't hold all of the routines in memory. As each routine was called, it's data was added to the memory stack until finally the code blew up with a stack overflow. I was wondering when the memory overflowed that the catch should fail to interupt the process and it is properly working. Again, it had nothing to do with the mathematical problem.
barneyman 21-Oct-11 2:53am    
an int is signed, its sign is marked by the most significant bit - if you overflow and set that bit, you get a negative number - it's well documented 'nuance' of c,c++ and c#

SQL is simply catching the overflow and asserting a fault - a feature of that language
KP Lee 21-Oct-11 3:53am    
barneyman "SQL is simply catching the overflow and asserting a fault - a feature of that language"
EXACTLY, however it should be a feature of the OS' mathematical process. Since it ISN'T, shouldn't the burden of doing mathematical processes correctly be handled by the language? If it doesn't do so, isn't that a bug in that language? Say you had a 3 bit signed 2's comp int. The valid range of numbers is 3 to -4. Do you think it is acceptable that 3 + 1 == -4? In my book, THAT is a bug.
barneyman 21-Oct-11 4:45am    
it's not a bug in the language - the language is working as specified

The fact you don't agree with it is rather moot

If you want a language that is more mathematically stringent, choose FORTRAN or similar
Sergey Alexandrovich Kryukov 21-Oct-11 15:33pm    
One practical resolution is using checked mode, as I just added to my solution.
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900