Compiling in checked and unckecked context - c#

What is the value of j?
Int32 i = Int32.MinValue;
Int32 j = -i;
Compiling in checked context will throw an exception.
In unchecked we obtain value Int32.MinValue.
But why so?

Here is min and max Int32 values:
Dec Bin (first bit is a sign bit)
Int32.MinValue -2147483648 10000000000000000000000000000000
Int32.MaxValue 2147483647 01111111111111111111111111111111
When you are trying to get -(-2147483648) with explicit overflow checking you get exception in this case, because 2147483648 is bigger than max allowed value for int type.
Then why you are getting MinValue when overflow is allowed? Because when Int32.MinValue is negated you have 2147483648 which has binary representation 10000000000000000000000000000000 but with signed integer first bit is a sign bit, so you get exactly Int32.Min value.
So, the problem here is treating first bit as number sign. If you would assign result of negated Int32.Min value to unsigned integer, you would get 2147483648 value, as expected:
Int32 i = Int32.MinValue;
UInt32 j = (UInt32)-i; // it has 32 bits and does not treat first bit as sign

This is an example of integer overflow. In a checked context, the integer overflow will be detected and converted to an exception, because the language designers decided so.
To explain integer overflow, you can do the calculation in binary by hand. To calculate -X, take X in binary, change all the 1's to 0's and 0's to 1's, then add 1 (the number 1, not a 1 bit).
Example: 5 = 00000000000000000000000000000101
flip all bits: 11111111111111111111111111111010
add one: 11111111111111111111111111111011 which is -5
Int32.MinValue = 10000000000000000000000000000000
flip all bits: 01111111111111111111111111111111
add one: 10000000000000000000000000000000
If you take Int32.MinValue and negate it, it doesn't change. -Int32.MinValue can't fit in an int - if you do -(Int64)Int32.MinValue it will work as expected.

Related

Issue with "arithmetic operation resulted in overflow"

I have this expression
long balance = (long)answer.Find(DppGlobals.TAG_TI_BALANCE).Get_QWORD();
which raises exception that there was overflow. The value on the right hand side is of unsigned type and has value: 18446744073708240732.
How to avoid this exception, use unchecked?
PS equivalent C++ implementation returned balance = -1310984, I need same value here too.
Why is there such an exception?
By using unchecked indeed now also on C# side I get -1310984. Can someone advice, am I losing data somehow?
Using uncheck will also crop your value, but you will not have an exception,you will get wrong number.I think you will do something changing your code, not mask your exception.
long balance = (unchecked))(long)answer.Find(DppGlobals.TAG_TI_BALANCE).Get_QWORD());
Why is there such an exception?
It is a very good that you get an error.Because if you are working in the sphere where everything is numbers, you can have a mistake and don't understand this.So the RunTime will show you your eror
Given the comments, it sounds like you do just need to use unchecked arithmetic - but you should be concerned about the use of ulong in your API. If your aim is to just propagate 8 bytes of data, and interpret it as either an unsigned integer or a signed integer depending on context, then you're fine - so long as nothing performs arithmetic on it in the "wrong" form.
It's important to understand why this happens though, and it's much easier to explain that with small numbers. I'll use byte and sbyte as an example. The range of byte is 0 to 255 inclusive. The range of sbyte is -128 to 127 inclusive. Both can store 256 different values. No problem.
Now, using unchecked conversions, it's fine to say:
byte a = GetByteFromSomewhere();
sbyte b = (sbyte) a;
StoreSByteSomewhere(b);
...
sbyte b = GetSByteFromStorage();
byte a = (byte) b;
If that's all you're doing, that's fine. A byte value of -1 will become an sbyte value of 255 and vice versa - basically it's just interpreting the same bit pattern in different ways.
But if you're performing other operations on the value when it's being handled as the "wrong" type, then you could get unexpected answers. For example, consider "dividing by 3". If you divide -9 by 3, you get -3, right? Whereas if you have:
byte original = -9;
sbyte converted = (sbyte) original;
sbyte divided = converted / 3;
byte result = (byte) divided;
... then you end up with a result of -2 instead of -3, due to the way the arithmetic worked.
Now that's all for unchecked conversions. When you have a checked conversion, it doesn't just interpret the bits - it treats the value as a number instead. So for example:
// In a checked context...
byte a = 128;
sbyte b = (sbyte) a; // Bang! Exception
That's because 128 (as a number) is outside the range of sbyte. This is what's happening in your case - the number 18446744073708240732 is outside the range of long, so you're getting an exception. The checked conversion is treating it as a number which can be range-checked, rather than an unchecked conversion just reinterpreting the bits as a long (which leads to the negative number you want).

why 32-bit signed integer maximum value change to minimum value after increment by 1 in c#?

If I have integer variable with maximum value assigned it which is (2,147,483,647) for 32 bit integer, and if I am incrementing it by 1 then it turn to (-2147483648) negative value
code
int i = int.MaxValue; // i = 2,147,483,647
i = i + 1;
Response.Write(i); // i = -2,147,483,648
Can anyone explain me?
I did not find the exact reason for this change in values.
This is just integer overflow, where the value is effectively leaking into the sign bit. It's simpler to reason about it with sbyte, for example. Think about the bitwise representations of 127 and -127 as signed bytes:
127: 01111111
-128: 10000000
Basically the addition is performed as if with an infinite range, and then the result is truncated to the appropriate number of bits, and that value "interpreted" according to its type.
Note that this is all if you're executing in an unchecked context. In a checked context, an OverflowException will be thrown instead.
From section 7.8.4 of the C# 5 specification:
In a checked context, if the sum is outside the range of the result type, a System.OverflowException is thrown. In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.
in signed int, first bit shows the sign and the rests shows the number:
so, in 32bit int, first bit is the sign, so maxInt is: 2147483647 or 01111111111111111111111111111111,
and if we increment this number by 1 it will become: 10000000000000000000000000000000 which is - 2147483647

Why Int32.MaxValue = 2147483648? [duplicate]

This question already has answers here:
Why is the maximum value of an unsigned n-bit integer 2ⁿ-1 and not 2ⁿ?
(12 answers)
Closed 5 years ago.
I am wondering why largest possible value of Int32 in .NET is 2147483647 but not 2147483648. Because 2³¹ = 2147483648.
Thank you
An Int32 is stored in 32 bits, not 31 bits, and half of its range is taken by negative numbers. Out of the remaining range, you lose one value to zero, leaving 2147483647 as the highest positive number.
The range for an Int32 is -2147483648 to 2147483647.
It also includes zero 0 in the positive range. Hence the range is 0 to 2147483647 and since zero has been considered in the positive side hence towards negative side from '-1' to -2147483648.
So overall positive and negative side takes equal number of values.
The actual data of Int32 is stored in 31 bits, because regular Int32 should also hold negative numbers, 1 bit is used as a sign bit, 31 bits that remain are used as data. However, if you use unsigned Int32, then you will have a complete 32 bits of data in it.
It mean int can have maximum 2147483648 positive values starting from 0 to 2147483647, The int.Min is -2,147,483,648 as it does not include the 0

String to Int conversion: Convert.toInt16

This is the code.
CODE 1: cmd.Parameters.Add("#RateCenterID", OleDbType.Integer).Value = Convert.ToInt32(ratecenterid.Text);
CODE 2: cmd.Parameters.Add("#QuantityThreshold", OleDbType.Integer).Value = Convert.ToIn32(quantityThreshold.Text);
I get the following error in the CODE 2 but not in CODE 1
Error: Value was either too large or too small for an Int32.
kindly help me
Regards,
Arjun
Try entering a smaller or larger value in the quantityThreshold text box.
Update
Okay, reading your comment response to Saeed Amiri, 4036953909 is too large for an int - it's range is -2147483648 to 2147483647
You could use a uint which has a range 0 to 4294967295
Convert.ToUInt32(ratecenterid.Text)
Although you will likely need to change the parameter type to OleDbType.UnsignedInt as well.
From MSDN - Int32 Structure:
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. The .NET Framework also includes an unsigned 32-bit integer value type, UInt32, which represents values that range from 0 to 4,294,967,295.
You are trying to use a value that is not possible to represent as an Int32.
Not sure why your title is about Int16 as your code and error indicate you are using Int32 - regardless - Int16 has an much smaller range than Int32:
The Int16 value type represents signed integers with values ranging from negative 32768 through positive 32767.
You need to either use UInt32 or long.
sample value for "QuantityThreshold = 4036953909"
Right. That wouldn't fit into an Int16 (as per your title), which has a maximum value of 32767. That wouldn't even fit into an Int32 (as per your code) (max value 2,147,483,647). It would fit into a UInt32, and would easily fit into an Int64 - perhaps the latter is what you're really looking for?
(You should also clarify your qusetion - are you using Int32 or Int16?)
Your current value is within UInt32 scope, and OleDbType.Integer size is 4 byte and is mapped to Int32, if you want use UInt32 you should use UnsignedInt as your parameter type, and use UInt32 conversion:
cmd.Parameters.Add("#QuantityThreshold", OleDbType.UnsignedInt).Value =
Convert.ToUIn32(quantityThreshold.Text)
Int32 has a range of -2147483648 to 2147483647. You could use a larger type e.g., uint (0 to 4294967295) or long (-9.2233E+18 to 9.2233E+18).
Ref: Error: Value was either too large or too small for an Int32
That number is way to big for an int32. You should just store it as a
string.(varchar)
You got the why in the other answers but I didn't see anyone mentioning ToInt64. Simply change the ToInt32 to ToInt64 and also make sure that the datatype of #QuantityThreshold can handle it.
The Int64 value type represents integers with values ranging from negative 9,223,372,036,854,775,808 through positive 9,223,372,036,854,775,807.
To fix your problem you will have to put the validation on your textbox - quantityThreshold, it should have the value with in the range of Int32. or use a larger type.

int or uint or what

Consider this
int i = 2147483647;
var n = i + 3;
i = n;
Console.WriteLine(i); // prints -2147483646 (1)
Console.WriteLine(n); // prints -2147483646 (2)
Console.WriteLine(n.GetType()); // prints System.Int32 (3)
I am confused with following
(1) how could int hold the value -2147483646 ? (int range = -2,147,483,648 to 2,147,483,647)
(2) why does this print -2147483648 but not 2147483648 (compiler should
decide better type as int range
exceeds)
(3) if it is converted somewhere, why n.GetType() gives System.Int32
?
Edit1: Made the correction: Now you will get What I am Getting. (sorry for that)
var n = i + 1; to
var n = i + 3;
Edit2: One more thing, if it as overflow, why is an exception not raised ?
Addition: as the overflow occurs, is it not right to set the type for
var n
in statement var n = i + 3; to another type accordingly ?
you are welcome to suggest a better title, as this is not making sense to.... me at least
Thanks
Update: Poster fixed his question.
1) This is output is expected because you added 3 to int.MaxValue causing an overflow. In .NET by default this is a legal operation in unchecked code giving a wrap-around to negative values, but if you add a checked block around the code it will throw an OverflowException instead.
2) The type of a variable declared with var is determined at compile time not runtime. It's a rule that adding two Int32s gives an Int32, not a UInt32, an Int64 or something else. So even though at runtime you can see that the result is too big for an Int32, it still has to return an Int32.
3) It's not converted to another type.
1) -2147483646 is bigger than -2,147,483,648
2) 2147483648 is out of range
3) int is an alias for Int32
1)
First of all, the value in the variable is not -2147483646, it's -2147483648. Run your test again and check the result.
There is no reason that an int could not hold the value -2147483646. It's within the range -2147483648..2147483647.
2)
The compiler chooses the data type of the variable to be the type of the result of the expression. The expression returns an int value, and even if the compiler would choose a larger data type for the variable, the expression still returns an int and you get the same value as result.
It's the operation in the expression that overflows, it's not when the result is assigned to the variable that it overflows.
3)
It's not converted anywhere.
This is an overflow, your number wrapped around and went negative
This isn't the compiler's job, as a loop at runtime can cause the same thing
int is an alias or System.Int32 they are equivalent in .Net.
This is because of the bit representation
you use Int32 but the same goes for char (8 bits)
the first bit holds the sign, then the following bits hold the number
so with 7 bits you can represent 128 numbers 0111 1111
when you try the 129th, 1000 0001, the sign bits get set so the computer thinks its -1 instead
Arithmic operations in .NET don't change the actual type.
You start off with an (32bit) integer and the +3 isn't going to change that.
That's also why you get an unexpected round number when you do this:
int a = 2147483647;
double b = a / 4;
or
int a = 2147483647;
var b = a / 4;
for that matter.
EDIT:
There is no exception because .NET overflows the number.
The overflow exception will only occur at assignment operations or as Mark explains when you set the conditions to generate the exception.
If you want an exception to be thrown, write
abc = checked(i+3)
instead. That will check for overflows.
Also, in c#, the default setting is to not throw exceptions on overflows. But you can switch that option somewhere on your project's properties.
You could make this easier on us all by using hex notation.
Not everyone knows that the eighth Mersenne prime is 0x7FFFFFFF
Just sayin'

Categories

Resources