Multiplying two positive Int32 returns incorrect, negative answer?
Asked Answered
P

3

5

I'm coding in C# for Windows Phone 7.5; I am taking text from a text box, parsing it into an array, then converting each array element into an Int32 using Convert.ToInt32, then running the resulting Int32 values through a series of mathematical calculations, multiplying and adding the Int32 values to hardcoded numbers (all dependent upon what's selected in the UI).

All is well until I take the resulting calculations and multiply them together: I'm getting a negative number from multiplying two positive numbers! This is the only time I am doing any calculations with both of the numbers that originated in the method that uses the Convert.ToInt32 function. When they're added, subtracted, or even divided, the math comes out correctly. But when they're multiplied, no dice. The math is totally wrong; I double checked the math in LibreOffice Calc and it doesn't match. When stepping through the code, everything's correct until the numbers that originated in the method that uses the Convert.ToInt32 function are multiplied together. Any ideas?

Pogey answered 9/3, 2013 at 20:12 Comment(3)
Do you want to show us your code?Rossiter
It sounds like an overflow. Are you using large numbers?Tilefish
First off, do your arithmetic in longs, decimals or BigIntegers if you need accurate results that exceed the bounds of an int. Second, if you believe that the overflow is a bug and you want to find it, then put your arithmetic inside a checked { ... } block and any integer overflow will become an exception. That will help you find your bug.Scarron
N
16

The numbers are probably large enough to overflow Int32.MaxValue.

Consider:

var r = Int32.MaxValue / 2;     // r = 1073741823
var ans = r * 3;                // ans = -1073741827

The reason for this is that negative integers are represented with a 1 in the largest bit, so any multiplication which is larger than the maximum value will have a 1 in this position, which is interpreted as a negative value.

Overflow is a danger with all integral types (int, short, byte, sbyte, char, long, ulong, ushort, and uint). You could use a floating point type, like float or double, but this comes with other problems, like rounding and equality issues. You have to know what kind of numbers you expect, then you might use other types like long, uint, ulong or a floating point type like double or decimal. Ultimately, if you don't know what could happen, you need to write guard code on the input (e.g. wrap it in a checked { } block [thanks, @EricLippert]), and handle it when it is a value outside the range you've designed for.

EDIT: Another option in .Net 4.0+ is to use System.Numerics.BigInteger, which avoids any overflow, but can be slow.

Nakesha answered 9/3, 2013 at 20:14 Comment(1)
Thanks for the explanation. I may just use the System.Numerics.BigInteger when I'm multiplying. The app should be ok to take a small speed hit; and I shouldn't be getting large numbers too often.Pogey
A
3

The quick and dirty solution is just to cast one of the values to a long and then cast the result back to int, if possible.

Edit: There is no need to use BigInteger for this case as int x int can never overflow a long.

Amathiste answered 9/3, 2013 at 20:17 Comment(4)
Sometimes that's the quick and clean solution! :)Refresher
If he's already overflowing, it is already known to be not possible to have an int result.Nakesha
@codekaizen: But determining that from an unchecked operation might be more expensive. In checked context you will save the cost of an exception, which from my tests is faster.Amathiste
int.MinValue is -2^31 and its square is 2^62, well within the range of a long.Detention
R
0

Its probably a Integer overflow exception. It can occur even if you are storing the number in a variable that is big enough. Example(long,double etc)

int one = int.MaxValue;
int two = int.MaxValue;

long sum = (long)(one + two); //Returns -2, because the cast was after the sum
                             //(long) -2.

You can cast them before the sum and get the correct result

int one = int.MaxValue;
int two = int.MaxValue;

long sum = (long) one + (long)two; //Returns 4294967294, it casts both the 
                                   //integer to long and then adds them 
Residuum answered 25/6, 2016 at 15:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.