Average of 3 long integers

Ulugbek Umirov picture Ulugbek Umirov · May 30, 2014 · Viewed 8.9k times · Source

I have 3 very large signed integers.

long x = long.MaxValue;
long y = long.MaxValue - 1;
long z = long.MaxValue - 2;

I want to calculate their truncated average. Expected average value is long.MaxValue - 1, which is 9223372036854775806.

It is impossible to calculate it as:

long avg = (x + y + z) / 3; // 3074457345618258600

Note: I read all those questions about average of 2 numbers, but I don't see how that technique can be applied to average of 3 numbers.

It would be very easy with the usage of BigInteger, but let's assume I cannot use it.

BigInteger bx = new BigInteger(x);
BigInteger by = new BigInteger(y);
BigInteger bz = new BigInteger(z);
BigInteger bavg = (bx + by + bz) / 3; // 9223372036854775806

If I convert to double, then, of course, I lose precision:

double dx = x;
double dy = y;
double dz = z;
double davg = (dx + dy + dz) / 3; // 9223372036854780000

If I convert to decimal, it works, but also let's assume that I cannot use it.

decimal mx = x;
decimal my = y;
decimal mz = z;
decimal mavg = (mx + my + mz) / 3; // 9223372036854775806

Question: Is there a way to calculate the truncated average of 3 very large integers only with the usage of long type? Don't consider that question as C#-specific, just it is easier for me to provide samples in C#.

Answer

Patrick Hofman picture Patrick Hofman · May 30, 2014

This code will work, but isn't that pretty.

It first divides all three values (it floors the values, so you 'lose' the remainder), and then divides the remainder:

long n = x / 3
         + y / 3
         + z / 3
         + ( x % 3
             + y % 3
             + z % 3
           ) / 3

Note that the above sample does not always work properly when having one or more negative values.

As discussed with Ulugbek, since the number of comments are exploding below, here is the current BEST solution for both positive and negative values.

Thanks to answers and comments of Ulugbek Umirov, James S, KevinZ, Marc van Leeuwen, gnasher729 this is the current solution:

static long CalculateAverage(long x, long y, long z)
{
    return (x % 3 + y % 3 + z % 3 + 6) / 3 - 2
            + x / 3 + y / 3 + z / 3;
}

static long CalculateAverage(params long[] arr)
{
    int count = arr.Length;
    return (arr.Sum(n => n % count) + count * (count - 1)) / count - (count - 1)
           + arr.Sum(n => n / count);
}