2

I don't seem to find accurate result in arithmetic operation using Int64 var. I need to do average of two Int64 values.

static void Main(string[] args)
{
    Int64 avg
    int testCase = 0;
    testCase = int.Parse(Console.ReadLine());

    for (int i = 0; i < testCase; i++)
    {
        string[] str = Console.ReadLine().Split();

        avg = ( ( Int64.Parse( str[0] ) + Int64.Parse( str[1] ) ) / 2 );

        Console.WriteLine(avg);
    }
}

Input: str[0] == 9082296538332151448 str[1] == 5601337573664003844

Output: -1881554980856698162

Why it's resulting in negative number. Trying to find the average

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Mendax
  • 35
  • 7
  • 13
    `9082296538332151448 + 5601337573664003844 > Int64.MaxValue`, you have integer overflow. – Dmitry Bychenko Oct 22 '19 at 14:46
  • 2
    Can you specify exactly what input you provide? If I provide just one of those two numbers, it throws OverflowException as 9082296538332151448 cannot fit into an int. Additionally, the code won't compile as you're missing a semicolon after `Int64 avg` which makes me worry that the code in the question is not your real code. Can you post a [mcve] that doesn't rely on user input but hardcodes the input instead? – Lasse V. Karlsen Oct 22 '19 at 14:46
  • 1
    some info here: https://chodounsky.net/2014/01/22/arithmetic-overflow-in-c-number/ – Tim Rutter Oct 22 '19 at 14:46
  • Note that `(9082296538332151448m + 5601337573664003844m) / 2 == 7341817055998077646`; `Decimal` has enough precision for this. Note however that even `Decimal`'s precision is not unlimited -- for more you can switch to `BigInteger`. – Jeroen Mostert Oct 22 '19 at 14:52
  • semicolon missing must have removed it when posting. sorry for the mistake. apart from that, number that you tried in Int will not fit unless one uses Int64 . – Mendax Oct 22 '19 at 14:53
  • Possible duplicate of [Best way to handle Integer overflow in C#?](https://stackoverflow.com/questions/2954970/best-way-to-handle-integer-overflow-in-c) – Trevor Oct 22 '19 at 14:56

1 Answers1

6

You have integer overflow:

9082296538332151448 + 5601337573664003844 > Int64.MaxValue

i.e.

14683634111996155292 > 9223372036854775807

you can use checked keyword in order to throw exception (ArithmeticException) in such a case (and know that something went wrong):

avg = checked( ( Int64.Parse( str[0] ) + Int64.Parse( str[1] ) ) / 2 );

If both str[0] and str[1] are guaranteed to be equal or under Int64.MaxValue you can put it as

Int64 arg1 = Int64.Parse(str[0]);
Int64 arg2 = Int64.Parse(str[1]); 

arg = checked(arg1 / 2 + arg2 / 2 + (arg1 % 2 + arg2 % 2) / 2);

In general case it can be something like this:

Int64[] data = ... 

Int64 average = 0;
Int64 rem = 0;

foreach (var item in data) {
  rem     += item % data.Length;
  average += item / data.Length + rem / data.Lenth;
  rem     %= data.Lenth; 
}   

if (rem > data.Length % 2L)
  average += 1;
else if (-rem > data.Length % 2L)
  average -= 1;  

Finally, another (slower but universal) possibility is to use BigIntegers instead of Int64:

using System.Numerics;

...

avg = (Int64)( ( BigInteger.Parse( str[0] ) + BigInteger.Parse( str[1] ) ) / 2 );
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215