2

Currently, I am having a bit of a problem with my C# code. I have a set of code that is supposed to turn a string in the form of "x^y^z..." into a number, so I have set up a method that looks like this.

public long valueOfPower()
{
    long[] number = Array.ConvertAll(this.power.Split('^'), long.Parse);
    if(number.Length == 1)
    {
        return number[0];
    }
    long result = number[0];
    long power = number[number.Length-1];
    for (long i = number.Length-1; i > 1; i-- )
    {
        power = (long)Math.Pow((int)number[(int)i-1], (int)power);
    }
    result= (long)Math.Pow((int)result,(int)power);
    return result;
}

The problem I am having is that when something like 2^2^2^2^2 is entered, I get an extremely large negative number. I am not sure if it is something wrong with my code, or because 2^2^2^2^2 is too large of a number for the long object, but I don't understand what is happening.

So, the question is, why is my code returning a large negative number when "this.power" is 2^2^2^2^2, but normal numbers with smaller inputs(like 2^2^2^2)? (Sorry about the random casting, that came from me experimenting with different number types.)

SquirtleGun
  • 57
  • 2
  • 8

3 Answers3

6

What is happening is overflow. Each data type is stored as a certain number of bits. Because that number of bits is limited, the biggest number any data type can store is limited. Because the most significant bit often represents the sign of the number, when the maximum value for a data type is exceeded, that bit flips and the computer now interprets it as a negative number.

You can use the checked keyword to throw an exception if your math would overflow. More info on that here: https://msdn.microsoft.com/en-us/library/74b4xzyw.aspx

Another possible solution would be using a BigInteger. More info here: https://msdn.microsoft.com/en-us/library/system.numerics.biginteger.aspx

See this for the max values of data types in C#: http://timtrott.co.uk/data-types-ranges/

See this for more info on overflow: https://en.wikipedia.org/wiki/Integer_overflow

nhouser9
  • 6,730
  • 3
  • 21
  • 42
  • 1
    Though the `checked` keyword can help, I recommend to open the `Property` page of the project, go to `Build`, click on `Advanced` (bottom right), and then check `Check for arithmetic overflow/underflow`. Make sure you do that for all configurations. – Bernhard Hiller Nov 15 '16 at 10:26
  • @BernhardHiller Good tip. I didn't know about that one actually – nhouser9 Nov 15 '16 at 14:46
0

2^2^2^2^2 is, well, quite a large number and as a result is overflowing the maximum length of the long data type (9,223,372,036,854,775,807) but some margin.

You could try using the BigInteger class out of System.Numerics, or come up with some other method of representing such a number.

Steve
  • 9,335
  • 10
  • 49
  • 81
0

The Overflow problem you are experiencing is because you are doing downcasting.

number and power are supposed to be long, but in your calculation, for ex:

power = (long)Math.Pow((int)number[(int)i-1], (int)power);
// you are downcasting number and power into int.

when you do calculation in int, then your value will become negative because of overflow, and then you convert it back to long.

Also, my Math.Pow only accepts double as parameter and returns double. I don't know how you are allowed to provide int as parameters.

So, to fix your issue, it should look like this:

power = (long)Math.Pow((double)number[(int)i-1], (double)power);
// and
result= (long)Math.Pow((double)result,(double)power);

Then, if you want to get something bigger than long, consider using BigInteger.

kurakura88
  • 2,185
  • 2
  • 12
  • 18