104

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#.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
Ulugbek Umirov
  • 12,719
  • 3
  • 23
  • 31

12 Answers12

143

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);
}
Community
  • 1
  • 1
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • 1
    @DavidG: No, since it adds all three, so you get the average per variable. – Patrick Hofman May 30 '14 at 08:13
  • 3
    @DavidG No. In math, `(x + y + z) / 3 = x / 3 + y / 3 + z / 3`. – Kris Vandermotten May 30 '14 at 08:14
  • 5
    I used Z3 to prove this correct for all variable counts between 1 and 5. – usr May 30 '14 at 14:10
  • 5
    Of course this appears to work, but the way integer truncation operates will screw you up. ``f(1,1,2) == 1`` while ``f(-2,-2,8) == 2`` – KevinZ May 30 '14 at 15:13
  • 11
    Note that due to brain-damaged semantics of the modulo operation, this can give a result that is off by one, namely rounded up rather than down, if negative values for the variables are allowed. For instance if x,y are positive multiples of 3, and z is -2, you get `(x+y)/3` which is too much. – Marc van Leeuwen May 30 '14 at 15:15
  • Z3 provides the following counter-example for signed bitvector arithmetic: `12, 19, -14`. Correct would be `5`, the trick gives `6` and naive average gives `5`. – usr May 30 '14 at 15:27
  • Hi guys, thanks for the input. Working on an improvement for negative values. – Patrick Hofman May 30 '14 at 15:29
  • @MarcvanLeeuwen I'd say it's very well defined: the quotient in signed integer division truncates toward 0, and the modulo residue is whatever that it needs to be so that ``divisor * quotient + residue == dividend``. Thus, you necessarily end up with ``sign(quotient) == sign(dividend) * sign(divisor)`` and ``sign(residue) == sign(dividend)`` – KevinZ May 30 '14 at 15:32
  • 2
    @KevinZ: That the remainder operator is well-defined does not distract from the fact that the remainder operator is seldom useful outside those cases where it mirrors what a modulo operator would do. Personally, I think languages should have separate operators for floored division, Euclidian division, real division (with a result coercible to `double` or `float` as needed), modulus, and Euclidian remainder. In many cases, remainder requires the compiler to produce special-case code for negative dividends; it's silly to have the compiler produce special-case code... – supercat May 30 '14 at 16:47
  • 6
    @KevinZ: ...whose effect then has to be undone by a programmer who never wanted that special-case behavior in the first place. Letting the programmer specify modulus rather than having to derive it from a remainder which the compiler may have derived from modulus would seem helpful. – supercat May 30 '14 at 16:48
  • 2
    Fix it by writing (x % 3 + y % 3 + z % 3 + 6) / 3 - 2. And add it as the first term, otherwise if x == y == z == LONG_MIN, x/3 + y/3 + z/3 could be an underflow. – gnasher729 May 30 '14 at 16:49
  • @supercat The built-in (integer) types are built for speed and predictability. The other operations you mentioned, are very easily composable. Floor can be: `x/y - ((x%y)<0)`. No idea what you mean by "euclidean division". "Coercible to float" division - what's wrong with floating the operands before you divide? – KevinZ May 30 '14 at 17:27
  • @KevinZ: For most constant values of `N`, the optimal code to compute (x floordiv N) and (x mod N) is significantly shorter and faster than the optimal code to compute (x truncdiv N) and (x rem N). Composing what should be a fast operation out of two slow operations doesn't seem like a recipe for speed. One can compute (x floordiv N) as `(x>>31)^((x ^ (x>>31)/N)`, thus only needing one slow operation, but if one could write `x floordiv N` code could be faster *and* more readable. As for "real division", having `x/y` yield a floating-point result for any numeric x and y... – supercat May 30 '14 at 17:52
  • ...and using some other operator for integer division, would mean that a reviewer seeing `double1 = int1/int2` wouldn't have to guess whether the programmer *meant* `double1 = (double)int1/int2`. In Pascal, the expressions `real1 = int1 div int2;` and `real1 = int1/int2;` have different meanings, and a programmer is unlikely to accidentally use one when the other is desired; a programmer who accidentally writes `int1 = int2/int3;` would receive an error, which would be a cue rewrite it, probably as either `int1 = Round(int2/int3);` or `int1 = int2 div int3;` depending upon desired semantics. – supercat May 30 '14 at 18:01
  • @supercat I usually argue that languages like C# should not have div and mod operators at all. They are very rarely used. They could be methods on the `Math` class recognized by the JIT. (For the same reason we don't have a pow operator in C#.) – usr May 30 '14 at 18:20
  • @usr: Rather than being methods in `Math`, I think it would be better to have them as methods on the numeric types; I also think rather than having explicit casts defined from floating-point types to integer types, the floating-point types should have included methods to floor, truncate, or round to the various integer types (e.g. `var = (q*2.5).TruncInt32` would yield an `Int32`). It would be nicer if `long a=(q*2.5).Trunc(); int b=(q*2.5).Trunc();` could work, but that couldn't happen without making `var c=(q*2.5).Trunc();` yield bizarre behavior. – supercat May 30 '14 at 18:41
  • @supercat all of this I agree with. Too late. – usr May 30 '14 at 18:42
  • 1
    @usr: BTW, a caveat with using such methods would be that at present, constant expressions are not allowed to contain method calls. Conceptually I think it would be fine to use method-call syntax for intrinsic operations on primitive types, and allow such intrinsic methods within constant expressions (the inability to compute powers in compile-time constant expressions is a semantic weakness in C# compared with VB.NET), but I don't know that any methods are at present handled in such fashion. – supercat May 30 '14 at 18:51
  • @supercat Whether "truncated signed two's complement integer division" is faster or slower than "floored signed two's complement integer division" in hardware, I am not qualified to comment on; but I suspect your reasoning to be somewhat ... unlikely to be true. – KevinZ May 30 '14 at 18:59
  • 1
    @supercat As for your suggestion of yielding floating point results by default in division with integral operands, I simply could not possibly agree. Fundamentally, integers are supposed to designate state and/or discrete quantity, while floating point meant magnitude and/or scalar. To have a a basic arithmetic operation like division not be closed under integers seem insane, apart from the fact that the floating point casting is incredibly slow. – KevinZ May 30 '14 at 19:04
  • @KevinZ: Truncated division by an unknown quantity, and the associated remainder operation, are generally a tiny bit faster than floored division and modulus; the differences are a small portion of the overall times, since all such operations are slow. For constant powers of two, floored division and modulus are generally about 3-4 times as fast as truncated division and remainder [(x floordiv 8) and (x mod 8) are `x>>3` and `x&7` respectively]; for non-power-of-two constants, the speed difference usually isn't quite as great but can still be significant. – supercat May 30 '14 at 19:18
  • @KevinZ: Historically, there have been some processors where floating-point operations were faster than integer operations (the rounding form would generally only have been encouraged on those). Otherwise, I agree that integer code generally expects discrete things, and should generally use `div` to indicate that. In Pascal (or VB.NET for that matter) the only time `/` may legally be used with integer operands is if the result is given to code that expects a floating-point value, and in the rare cases where a programmer wants to store a truncated quotient in a floating-point variable... – supercat May 30 '14 at 19:23
  • 1
    @supercat and company: please don't delete your comments accidentally, I need time to digest all your discussion. – Ulugbek Umirov May 30 '14 at 19:24
  • ...I think it's better to make such intention explicit than have that be the default behavior *when a quotient is given to code expecting a floating-point value*. – supercat May 30 '14 at 19:30
  • @supercat I wasn't talking about fp division being slow, I was talking about the fp cast. It only gets worse if you want to convert that float back to an int. On floor being faster than trunc, you are probably right. – KevinZ May 30 '14 at 20:23
  • I believe the new formula has the following counter-example: 0xff720000, 0xfc71cfdf, 0xfb5bb020. Should evaluate to 4246022827 but evaluates to 4246022826 instead. With 4-bit numbers 2, 5, -8 are also a counter-example. It is easier to understand. – usr May 30 '14 at 22:52
  • @supercat "Composing what should be a fast operation out of two slow operations doesn't seem like a recipe for speed." You would think that, but for C/C++ at least, GCC will turn (x << 1) | (x >> 31) into a single instruction. – Miles Rout Jun 03 '14 at 04:11
  • I'm a bit faster, see my solution below. – maaartinus Sep 04 '14 at 20:52
27

NB - Patrick has already given a great answer. Expanding on this you could do a generic version for any number of integers like so:

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

long[] arr = { x, y, z };
var avg = arr.Select(i => i / arr.Length).Sum() 
        + arr.Select(i => i % arr.Length).Sum() / arr.Length;
Community
  • 1
  • 1
James S
  • 3,558
  • 16
  • 25
7

Patrick Hofman has posted a great solution. But if needed it can still be implemented in several other ways. Using the algorithm here I have another solution. If implemented carefully it may be faster than the multiple divisions in systems with slow hardware divisors. It can be further optimized by using divide by constants technique from hacker's delight

public class int128_t {
    private int H;
    private long L;

    public int128_t(int h, long l)
    {
        H = h;
        L = l;
    }

    public int128_t add(int128_t a)
    {
        int128_t s;
        s.L = L + a.L;
        s.H = H + a.H + (s.L < a.L);
        return b;
    }

    private int128_t rshift2()  // right shift 2
    {
        int128_t r;
        r.H = H >> 2;
        r.L = (L >> 2) | ((H & 0x03) << 62);
        return r;
    }

    public int128_t divideby3()
    {
        int128_t sum = {0, 0}, num = new int128_t(H, L);
        while (num.H || num.L > 3)
        {
            int128_t n_sar2 = num.rshift2();
            sum = add(n_sar2, sum);
            num = add(n_sar2, new int128_t(0, num.L & 3));
        }

        if (num.H == 0 && num.L == 3)
        {
            // sum = add(sum, 1);
            sum.L++;
            if (sum.L == 0) sum.H++;
        }
        return sum; 
    }
};

int128_t t = new int128_t(0, x);
t = t.add(new int128_t(0, y));
t = t.add(new int128_t(0, z));
t = t.divideby3();
long average = t.L;

In C/C++ on 64-bit platforms it's much easier with __int128

int64_t average = ((__int128)x + y + z)/3;
Community
  • 1
  • 1
phuclv
  • 37,963
  • 15
  • 156
  • 475
  • 2
    I would suggest that a good way of dividing a 32-bit unsigned value by 3 is to multiply by 0x55555555L, add 0x55555555, and shift right by 32. Your divideby3 method, by comparison, looks as though it would require many discrete steps. – supercat May 30 '14 at 15:59
  • @supercat yes I know that method. The method by hacker's delight is even more correct but I'll the implementation for another time – phuclv May 30 '14 at 16:10
  • I'm not sure what "more correct" means. Reciprocal multiplies can in many cases yield exact values directly, or else yield values which can be refined in one or two steps. BTW, I think I should have suggested multiplying by 0x55555556, which would then yield exact results without needing an "add". Also, is your loop condition correct? What modifies H and L in the loop? – supercat May 30 '14 at 16:53
  • Incidentally, even if one doesn't have a hardware multiply, one can quickly approximate an unsigned `x=y/3` via `x=y>>2; x+=x>>2; x+=x>>4; x+=x>>8; x+=x>>16; x+=x>>32;`. The result will be very close to x, and can be made precise by computing `delta=y-x-x-x;` and using adjusting `x` as needed. – supercat May 30 '14 at 17:15
  • Any decent compiler will calculate x / 3 and x % 3 with the fastest possible code anyway, using all the tricks in the book. – gnasher729 May 30 '14 at 23:36
  • @supercat I mean in the hacker's delight solution there's an adjusting step of `return q + (11*r >> 5);` while most solutions on the internet are just multiplying by 0x55555556 and I didn't know if it's as correct as the other one – phuclv May 31 '14 at 01:46
  • 1
    @gnasher729 I wonder if it can use that optimization in 32-bit computers since it often cannot do 64x64→128 bit multiplication – phuclv May 31 '14 at 01:58
7

You can calculate the mean of numbers based on the differences between the numbers rather than using the sum.

Let's say x is the max, y is the median, z is the min (as you have). We will call them max, median and min.

Conditional checker added as per @UlugbekUmirov's comment:

long tmp = median + ((min - median) / 2);            //Average of min 2 values
if (median > 0) tmp = median + ((max - median) / 2); //Average of max 2 values
long mean;
if (min > 0) {
    mean = min + ((tmp - min) * (2.0 / 3)); //Average of all 3 values
} else if (median > 0) {
    mean = min;
    while (mean != tmp) {
        mean += 2;
        tmp--;
    }
} else if (max > 0) {
    mean = max;
    while (mean != tmp) {
        mean--;
        tmp += 2;
    }
} else {
    mean = max + ((tmp - max) * (2.0 / 3));
}
La-comadreja
  • 5,627
  • 11
  • 36
  • 64
6

Patching Patrick Hofman's solution with supercat's correction, I give you the following:

static Int64 Avg3 ( Int64 x, Int64 y, Int64 z )
{
    UInt64 flag = 1ul << 63;
    UInt64 x_ = flag ^ (UInt64) x;
    UInt64 y_ = flag ^ (UInt64) y;
    UInt64 z_ = flag ^ (UInt64) z;
    UInt64 quotient = x_ / 3ul + y_ / 3ul + z_ / 3ul
        + ( x_ % 3ul + y_ % 3ul + z_ % 3ul ) / 3ul;
    return (Int64) (quotient ^ flag);
}

And the N element case:

static Int64 AvgN ( params Int64 [ ] args )
{
    UInt64 length = (UInt64) args.Length;
    UInt64 flag = 1ul << 63;
    UInt64 quotient_sum = 0;
    UInt64 remainder_sum = 0;
    foreach ( Int64 item in args )
    {
        UInt64 uitem = flag ^ (UInt64) item;
        quotient_sum += uitem / length;
        remainder_sum += uitem % length;
    }

    return (Int64) ( flag ^ ( quotient_sum + remainder_sum / length ) );
}

This always gives the floor() of the mean, and eliminates every possible edge case.

Community
  • 1
  • 1
KevinZ
  • 3,036
  • 1
  • 18
  • 26
  • 1
    I translated AvgN to Z3 code and proved this correct for all reasonable input sizes (e.g. 1 <= args.Length <= 5 and bitvector size of 6). This answer is correct. – usr May 30 '14 at 23:16
  • Wonderful answer Kevin. Thanks for your contribution! http://meta.stackoverflow.com/a/303292/993547 – Patrick Hofman Aug 24 '15 at 12:34
5

Because C uses floored division rather than Euclidian division, it may easier to compute a properly-rounded average of three unsigned values than three signed ones. Simply add 0x8000000000000000UL to each number before taking the unsigned average, subtract it after taking the result, and use an unchecked cast back to Int64 to get a signed average.

To compute the unsigned average, compute the sum of the top 32 bits of the three values. Then compute the sum of the bottom 32 bits of the three values, plus the sum from above, plus one [the plus one is to yield a rounded result]. The average will be 0x55555555 times the first sum, plus one third of the second.

Performance on 32-bit processors might be enhanced by producing three "sum" values each of which is 32 bits long, so that the final result is ((0x55555555UL * sumX)<<32) + 0x55555555UL * sumH + sumL/3; it might possibly be further enhanced by replacing sumL/3 with ((sumL * 0x55555556UL) >> 32), though the latter would depend upon the JIT optimizer [it might know how to replace a division by 3 with a multiply, and its code might actually be more efficient than an explicit multiply operation].

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
supercat
  • 77,689
  • 9
  • 166
  • 211
  • After adding 0x8000000000000000UL doesn't the overflow affect the result? – phuclv May 31 '14 at 02:01
  • @LưuVĩnhPhúc There is no overflow. Go to [my answer](http://stackoverflow.com/questions/23949785/average-of-3-long-integers/23964161#23964161) for an implementation. The splitting into 2 32 bit int was unnecessary though. – KevinZ May 31 '14 at 02:58
  • @KevinZ: Splitting each value into an upper and lower 32-bit part is faster than splitting it into a divide-by-three quotient and remainder. – supercat May 31 '14 at 05:13
  • why doesn't it overflow? for numbers with the highest bit = 1 then it'll cause a carry to the next bit (which is discarded) and wraparound. I don't understand why only dividing the low bits doesn't change the result – phuclv May 31 '14 at 05:30
  • @LưuVĩnhPhúc: Adding that constant to a positive-valued long will not overflow because the result will fit in an unsigned long. Adding that constant to a negative-valued long will cause that value to be converted to an unsigned long which is the additive inverse of the corresponding positive value. Switching to 16 bits for brevity, adding -3 to 0x8000u will coerce the -3 to 0xFFFDu because adding 3 to 0xFFFDu will yield 0. Adding 0xFFFD to 0x8000u will yield 0x7FFDu, which is 3 less than 0x8000u. – supercat May 31 '14 at 05:44
  • 1
    @LưuVĩnhPhúc: Unlike signed values which behave semantically like numbers and are not allowed to overflow in a legitimate C program, unsigned values generally behave like members of a wrapping abstract algebraic ring, so the wrapping semantics are well defined. – supercat May 31 '14 at 05:45
  • I know about the wrapping of unsigned numbers but I don't know why adding 0x8000 produce a rounded result. Take the tuple (0xFFFD, 0xFFFF, 0xFFFE) for example, after adding 0x8000 to the three and add we have `0x7FFD + 0x7FFF + 0x7FFE = 0x17FFA`. `0x7FFA/3 - 0x8000 = 0xAAA8` which isn't a correct result – phuclv May 31 '14 at 08:47
  • 1
    The tuple represents -3, -2, -1. After having added 0x8000U to each value, the values should then be split in half: 7F+FF 7F+FE 7F+FD. Add the upper and lower halves, yielding 17D + 2FA. Add the top-half sum to the bottom-half sum yielding 477. Multiply 17D by 55 yielding 7E81. Divide 477 by three yielding 17D. Add 7E81 to 17D yielding 7FFE. Subtract 8000 from that and get -2. – supercat May 31 '14 at 19:51
5

If you know you have N values, can you just divide each value by N and sum them together?

long GetAverage(long* arrayVals, int n)
{
    long avg = 0;
    long rem = 0;

    for(int i=0; i<n; ++i)
    {
        avg += arrayVals[i] / n;
        rem += arrayVals[i] % n;
    }

    return avg + (rem / n);
}
abelenky
  • 63,815
  • 23
  • 109
  • 159
  • this is just the same as Patrick Hofman's solution, if not less correct that the final version – phuclv Jun 06 '14 at 02:37
4

You could use the fact that you can write each of the numbers as y = ax + b, where x is a constant. Each a would be y / x (the integer part of that division). Each b would be y % x (the rest/modulo of that division). If you choose this constant in an intelligent way, for example by choosing the square root of the maximum number as a constant, you can get the average of x numbers without having problems with overflow.

The average of an arbitrary list of numbers can be found by finding:

( ( sum( all A's ) / length ) * constant ) + 
( ( sum( all A's ) % length ) * constant / length) +
( ( sum( all B's ) / length )

where % denotes modulo and / denotes the 'whole' part of division.

The program would look something like:

class Program
{
    static void Main()
    {
        List<long> list = new List<long>();
        list.Add( long.MaxValue );
        list.Add( long.MaxValue - 1 );
        list.Add( long.MaxValue - 2 );

        long sumA = 0, sumB = 0;
        long res1, res2, res3;
        //You should calculate the following dynamically
        long constant = 1753413056;

        foreach (long num in list)
        {
            sumA += num / constant;
            sumB += num % constant;
        }

        res1 = (sumA / list.Count) * constant;
        res2 = ((sumA % list.Count) * constant) / list.Count;
        res3 = sumB / list.Count;

        Console.WriteLine( res1 + res2 + res3 );
    }
}
Sumurai8
  • 20,333
  • 11
  • 66
  • 100
2

I also tried it and come up with a faster solution (although only by a factor about 3/4). It uses a single division

public static long avg(long a, long b, long c) {
    final long quarterSum = (a>>2) + (b>>2) + (c>>2);
    final long lowSum = (a&3) + (b&3) + (c&3);
    final long twelfth = quarterSum / 3;
    final long quarterRemainder = quarterSum - 3*twelfth;
    final long adjustment = smallDiv3(lowSum + 4*quarterRemainder);
    return 4*twelfth + adjustment;
}

where smallDiv3 is division by 3 using multipliation and working only for small arguments

private static long smallDiv3(long n) {
    assert -30 <= n && n <= 30;
    // Constants found rather experimentally.
    return (64/3*n + 10) >> 6;
}

Here is the whole code including a test and a benchmark, the results are not that impressive.

maaartinus
  • 44,714
  • 32
  • 161
  • 320
1

This function computes the result in two divisions. It should generalize nicely to other divisors and word sizes.

It works by computing the double-word addition result, then working out the division.

Int64 average(Int64 a, Int64 b, Int64 c) {
    // constants: 0x10000000000000000 div/mod 3
    const Int64 hdiv3 = UInt64(-3) / 3 + 1;
    const Int64 hmod3 = UInt64(-3) % 3;

    // compute the signed double-word addition result in hi:lo
    UInt64 lo = a; Int64 hi = a>=0 ? 0 : -1;
    lo += b; hi += b>=0 ? lo<b : -(lo>=UInt64(b));
    lo += c; hi += c>=0 ? lo<c : -(lo>=UInt64(c));

    // divide, do a correction when high/low modulos add up
    return hi>=0 ? lo/3 + hi*hdiv3 + (lo%3 + hi*hmod3)/3
                 : lo/3+1 + hi*hdiv3 + Int64(lo%3-3 + hi*hmod3)/3;
}
Řrřola
  • 6,007
  • 1
  • 17
  • 10
0

Math

(x + y + z) / 3 = x/3 + y/3 + z/3

(a[1] + a[2] + .. + a[k]) / k = a[1]/k + a[2]/k + .. + a[k]/k

Code

long calculateAverage (long a [])
{
    double average = 0;

    foreach (long x in a)
        average += (Convert.ToDouble(x)/Convert.ToDouble(a.Length));

    return Convert.ToInt64(Math.Round(average));
}

long calculateAverage_Safe (long a [])
{
    double average = 0;
    double b = 0;

    foreach (long x in a)
    {
        b = (Convert.ToDouble(x)/Convert.ToDouble(a.Length));

        if (b >= (Convert.ToDouble(long.MaxValue)-average))
            throw new OverflowException ();

        average += b;
    }

    return Convert.ToInt64(Math.Round(average));
}
Khaled.K
  • 5,828
  • 1
  • 33
  • 51
0

Try this:

long n = Array.ConvertAll(new[]{x,y,z},v=>v/3).Sum()
     +  (Array.ConvertAll(new[]{x,y,z},v=>v%3).Sum() / 3);
trinalbadger587
  • 1,905
  • 1
  • 18
  • 36