Take the 2-minute tour ×

Edit: Since it appears nobody is reading the original question this links to, let me bring in a synopsis of it here.

The original problem, as asked by someone else, was that, given a large number of values, where the sum would exceed what a data type of Double would hold, how can one calculate the average of those values.

There was several answers that said to calculate in sets, like taking 50 and 50 numbers, and calculating the average inside those sets, and then finally take the average of all those sets and combine those to get the final average value.

My position was that unless you can guarantee that all those values can be split into a number of equally sized sets, you cannot use this approach. Someone dared me to ask the question here, in order to provide the answer, so here it is.

Basically, given an arbitrary number of values, where:

  • I know the number of values beforehand (but again, how would your answer change if you didn't?`)
  • I cannot gather up all the numbers, nor can I sum them (the sum will be too big for a normal data type in your programming language)

how can I calculate the average?

The rest of the question here outlines how, and the problems with, the approach to split into equally sized sets, but I'd really just like to know how you can do it.

Note that I know perfectly well enough math to know that in math theory terms, calculating the sum of A[1..N]/N will give me the average, let's assume that there are reasons that it isn't just as simple, and I need to split up the workload, and that the number of values isn't necessarily going to be divisable by 3, 7, 50, 1000 or whatever.

In other words, the solution I'm after will have to be general.

From this question:

my position was that splitting the workload up into sets is no good, unless you can ensure that the size of those sets are equal.

Edit: The original question was about the upper limit that a particular data type could hold, and since he was summing up a lot of numbers (count that was given as example was 10^9), the data type could not hold the sum. Since this was a problem in the original solution, I'm assuming (and this is a prerequisite for my question, sorry for missing that) that the numbers are too big to give any meaningful answers.

So, dividing by the total number of values directly is out. The original reason for why a normal SUM/COUNT solution was out was that SUM would overflow, but let's assume, for this question that SET-SET/SET-SIZE will underflow, or whatever.

The important part is that I cannot simply sum, I cannot simply divide by the number of total values. If I cannot do that, will my approach work, or not, and what can I do to fix it?

Let me outline the problem.

Let's assume you're going to calculate the average of the numbers 1 through 6, but you cannot (for whatever reason) do so by summing the numbers, counting the numbers, and then dividing the sum by the count. In other words, you cannot simply do (1+2+3+4+5+6)/6.

In other words, SUM(1..6)/COUNT(1..6) is out. We're not considering NULL's (as in database NULL's) here.

Several of the answers to that question alluded to being able to split the numbers being averaged into sets, say 3 or 50 or 1000 numbers, then calculating some number for that, and then finally combining those values to get the final average.

My position is that this is not possible in the general case, since this will make some numbers, the ones appearing in the final set, more or less valuable than all the ones in the previous sets, unless you can split all the numbers into equally sized sets.

For instance, to calculate the average of 1-6, you can split it up into sets of 3 numbers like this:

/ 1   2   3 \   / 4   5   6 \
\ 3   3   3 /   \ 3   3   3 /  <-- 3 because 3 numbers in the set
      2               2        <-- 2 because 2 equally sized groups

Which gives you this:

      2               5
      -       +       - = 3.5
      2               2

(note: (1+2+3+4+5+6)/6 = 3.5, so this is correct here)

However, my point is that once the number of values cannot be split into a number of equally sized sets, this method falls apart. For instance, what about the sequence 1-7, which contains a prime number of values.

Can a similar approach, that won't sum all the values, and count all the values, in one go, work?

So, is there such an approach? How do I calculate the average of an arbitrary number of values in which the following holds true:

  1. I cannot do a normal sum/count approach, for whatever reason
  2. I know the number of values beforehand (what if I don't, will that change the answer?)
share|improve this question
@Lasse V. Karlsen: I just want you to see below (stackoverflow.com/questions/1931359/…) that I solved the general problem. You can use my method to compute the mean by partitioning a set however you like. In particular, my approach is amenable to parallelization. –  Jason Dec 19 '09 at 17:37
add comment

8 Answers

up vote 7 down vote accepted

Well, suppose you added three numbers and divided by three, and then added two numbers and divided by two. Can you get the average from these?

x = (a + b + c) / 3
y = (d + e) / 2
z = (f + g) / 2

And you want

r = (a + b + c + d + e + f + g) / 7

That is equal to

r = (3 * (a + b + c) / 3 + 2 * (d + e) / 2 + 2 * (f + g) / 2) / 7
r = (3 * x + 2 * y + 2 * z) / 7

Both lines above overflow, of course, but since division is distributive, we do

r = (3.0 / 7.0) * x + (2.0 / 7.0) * y + (2.0 / 7.0) * z

Which guarantees that you won't overflow, as I'm multiplying x, y and z by fractions less than one.

This is the fundamental point here. Neither I'm dividing all numbers beforehand by the total count, nor am I ever exceeding the overflow.

So... if you you keep adding to an accumulator, keep track of how many numbers you have added, and always test if the next number will cause an overflow, you can then get partial averages, and compute the final average.

And no, if you don't know the values beforehand, it doesn't change anything (provided that you can count them as you sum them).

Here is a Scala function that does it. It's not idiomatic Scala, so that it can be more easily understood:

def avg(input: List[Double]): Double = {
  var partialAverages: List[(Double, Int)] = Nil
  var inputLength = 0
  var currentSum = 0.0
  var currentCount = 0
  var numbers = input

  while (numbers.nonEmpty) {
    val number = numbers.head
    val rest = numbers.tail
    if (number > 0 && currentSum > 0 && Double.MaxValue - currentSum < number) {
      partialAverages = (currentSum / currentCount, currentCount) :: partialAverages
      currentSum = 0
      currentCount = 0
    } else if (number < 0 && currentSum < 0 && Double.MinValue - currentSum > number) {
      partialAverages = (currentSum / currentCount, currentCount) :: partialAverages
      currentSum = 0
      currentCount = 0
    currentSum += number
    currentCount += 1
    inputLength += 1
    numbers = rest
  partialAverages = (currentSum / currentCount, currentCount) :: partialAverages

  var result = 0.0
  while (partialAverages.nonEmpty) {
    val ((partialSum, partialCount) :: rest) = partialAverages
    result += partialSum * (partialCount.toDouble / inputLength)
    partialAverages = rest


EDIT: Won't multiplying with 2, and 3, get me back into the range of "not supporter by the data type?"

No. If you were diving by 7 at the end, absolutely. But here you are dividing at each step of the sum. Even in your real case the weights (2/7 and 3/7) would be in the range of manageble numbers (e.g. 1/10 ~ 1/10000) which wouldn't make a big difference compared to your weight (i.e. 1).

PS: I wonder why I'm working on this answer instead of writing mine where I can earn my rep :-)

share|improve this answer
This would have been more or less my answer that I am typing. Kudos to you for being faster (I'm discarding mine). Kudos also for the better notation :-) –  Davide Dec 19 '09 at 0:12
But won't that just get me back to my original problem? The original problem, as stated by the original question, is that the "Double" data type cannot hold the total sum to be averaged. When I multiply, in your code, won't that collide with the same limitations? –  Lasse V. Karlsen Dec 19 '09 at 0:14
@Lasse, there was a line which was overflowing, but it was unnecessary. I removed from the answer. –  Davide Dec 19 '09 at 0:21
... hmm, no it won't. I think I'm getting it now. –  Lasse V. Karlsen Dec 19 '09 at 0:22
Or perhaps not, won't multiplying with 2, and 3, get me back into the range of "not supporter by the data type?" –  Lasse V. Karlsen Dec 19 '09 at 0:31
show 1 more comment

If you know the number of values beforehand (say it's N), you just add 1/N + 2/N + 3/N etc, supposing that you had values 1, 2, 3. You can split this into as many calculations as you like, and just add up your results. It may lead to a slight loss of precision, but this shouldn't be an issue unless you also need a super-accurate result.

If you don't know the number of items ahead of time, you might have to be more creative. But you can, again, do it progressively. Say the list is 1, 2, 3, 4. Start with mean = 1. Then mean = mean*(1/2) + 2*(1/2). Then mean = mean*(2/3) + 3*(1/3). Then mean = mean*(3/4) + 4*(1/4) etc. It's easy to generalize, and you just have to make sure the bracketed quantities are calculated in advance, to prevent overflow.

Of course, if you want extreme accuracy (say, more than 0.001% accuracy), you may need to be a bit more careful than this, but otherwise you should be fine.

share|improve this answer
Let me augment the question, because that's not an option in this case. –  Lasse V. Karlsen Dec 19 '09 at 0:07
Note that your multiplication/division solution, for the case of the original question, will get into the same trouble eventually. At some point, the data type used to hold the value isn't going to have enough fidelity/range to hold the correct value. –  Lasse V. Karlsen Dec 19 '09 at 0:13
Let me give a reason why you might not want to do so: underflow (of course it doesn't apply for just 7 values) - see the original answer. –  Davide Dec 19 '09 at 0:14
Davide, that's a good point, one that I raised myself, but more of a concern. I did not object to the answers because of underflow, but just because I just did not understand how, given the premises that the total sum would overflow the data type, any sub-division would correctly work. But, as I said, it's sunday morning, 1 o'clock, and all that ;) –  Lasse V. Karlsen Dec 19 '09 at 0:26
@Lasse: In what time zone is it Sunday morning when it's Saturday morning UTC? –  P Daddy Dec 19 '09 at 2:44
add comment

Let X be your sample set. Partition it into two sets A and B in any way that you like. Define delta = m_B - m_A where m_S denotes the mean of a set S. Then

m_X = m_A + delta * |B| / |X|

where |S| denotes the cardinality of a set S. Now you can repeatedly apply this to partition and calculate the mean.

Why is this true? Let s = 1 / |A| and t = 1 / |B| and u = 1 / |X| (for convenience of notation) and let aSigma and bSigma denote the sum of the elements in A and B respectively so that:

  m_A + delta * |B| / |X|
= s * aSigma + u * |B| * (t * bSigma - s * aSigma)
= s * aSigma + u * (bSigma - |B| * s * aSigma)
= s * aSigma + u * bSigma - u * |B| * s * aSigma
= s * aSigma * (1 - u * |B|) + u * bSigma
= s * aSigma * (u * |X| - u * |B|) + u * bSigma
= s * u * aSigma * (|X| - |B|) + u * bSigma
= s * u * aSigma * |A| + u * bSigma
= u * aSigma + u * bSigma
= u * (aSigma + bSigma)
= u * (xSigma)
= xSigma / |X|
= m_X

The proof is complete.

From here it is obvious how to use this to either recursively compute a mean (say by repeatedly splitting a set in half) or how to use this to parallelize the computation of the mean of a set.

The well-known on-line algorithm for calculating the mean is just a special case of this. This is the algorithm that if m is the mean of {x_1, x_2, ... , x_n} then the mean of {x_1, x_2, ..., x_n, x_(n+1)} is m + ((x_(n+1) - m)) / (n + 1). So with X = {x_1, x_2, ..., x_(n+1)}, A = {x_(n+1)}, and B = {x_1, x_2, ..., x_n} we recover the on-line algorithm.

share|improve this answer
add comment

Thinking outside the box: Use the median instead. It's much easier to calculate - there are tons of algorithms out there (e.g. using queues), you can often construct good arguments as to why it's more meaningful for data sets (less swayed by extreme values; etc) and you will have zero problems with numerical accuracy. It will be fast and efficient. Plus, for large data sets (which it sounds like you have), unless the distributions are truly weird, the values for the mean and median will be similar.

share|improve this answer
+1 for thinking outside the box, but not +2 (oh how I wish I could award some answers +2 instead of just +1) because you're sidestepping my whole question, and since my question is on the premises that "this is what I want to do, damned if there are other ways to do it", then unfortunately it's not the right answer. –  Lasse V. Karlsen Dec 19 '09 at 0:24
add comment

When you split the numbers into sets you're just dividing by the total number or am I missing something?

You have written it as

/ 1   2   3 \   / 4   5   6 \
\ 3   3   3 /   \ 3   3   3 /
      2               2

but that's just

/ 1   2   3 \   / 4   5   6 \
\ 6   6   6 /   \ 6   6   6 /

so for the numbers from 1 to 7 one possible grouping is just

\ 7   7   7 /   \ 7   7   7 /   \ 7 /
share|improve this answer
add comment


Average of x_1 .. x_N
    = (Sum(i=1,N,x_i)) / N
    = (Sum(i=1,M,x_i) + Sum(i=M+1,N,x_i)) / N
    = (Sum(i=1,M,x_i)) / N + (Sum(i=M+1,N,x_i)) / N

This can be repeatedly applied, and is true regardless of whether the summations are of equal size. So:

  • Keep adding terms until both:
    • adding another one will overflow (or otherwise lose precision)
    • dividing by N will not underflow
  • Divide the sum by N
  • Add the result to the average-so-far

There's one obvious awkward case, which is that there are some very small terms at the end of the sequence, such that you run out of values before you satisfy the condition "dividing by N will not underflow". In which case just discard those values - if their contribution to the average cannot be represented in your floating type, then it is in particular smaller than the precision of your average. So it doesn't make any difference to the result whether you include those terms or not.

There are also some less obvious awkward cases to do with loss of precision on individual summations. For example, what's the average of the values:

10^100, 1, -10^100

Mathematics says it's 1, but floating-point arithmetic says it depends what order you add up the terms, and in 4 of the 6 possibilities it's 0, because (10^100) + 1 = 10^100. But I think that the non-commutativity of floating-point arithmetic is a different and more general problem than this question. If sorting the input is out of the question, I think there are things you can do where you maintain lots of accumulators of different magnitudes, and add each new value to whichever one of them will give best precision. But I don't really know.

share|improve this answer
add comment

Here's another approach. You're 'receiving' numbers one-by-one from some source, but you can keep track of the mean at each step.

First, I will write out the formula for mean at step n+1:

mean[n+1] = mean[n] - (mean[n] - x[n+1]) / (n+1)

with the initial condition:

mean[0] = x[0]

(the index starts at zero).

The first equation can be simplified to:

mean[n+1] = n * mean[n] / (n+1) + x[n+1]/(n+1)

The idea is that you keep track of the mean, and when you 'receive' the next value in your sequence, you figure out its offset from the current mean, and divide it equally between the n+1 samples seen so far, and adjust your mean accordingly. If your numbers don't have a lot of variance, your running mean will need to be adjusted very slightly with the new numbers as n becomes large.

Obviously, this method works even if you don't know the total number of values when you start. It has an additional advantage that you know the value of the current mean at all times. One disadvantage that I can think of is the it probably gives more 'weight' to the numbers seen in the beginning (not in a strict mathematical sense, but because of floating point representations).

Finally, all such calculations are bound to run into floating-point 'errors' if one is not careful enough. See my answer to another question for some of the problems with floating point calculations and how to test for potential problems.

As a test, I generated N=100000 normally distributed random numbers with mean zero and variance 1. Then I calculated their mean by three methods.

  1. sum(numbers) / N, call it m1,
  2. my method above, call it m2,
  3. sort the numbers, and then use my method above, call it m3.

Here's what I found: m1 − m2 ∼ −4.6×10−17, m1 − m3 ∼ −3×10−15, m2 − m3 ∼ −3×10−15. So, if your numbers are sorted, the error might not be small enough for you. (Note however that even the worst error is 10−15 parts in 1 for 100000 numbers, so it might be good enough anyway.)

share|improve this answer
add comment






class BigMeanSet{

    public double GetAverage(IEnumerable<uint> values){

        uint count = 0;

        foreach(uint value in values){
            Add(0, value);

        return DivideBy(count);

    void Add(int listIndex, uint value){
            if(list.Count == listIndex + 1)
            Add(listIndex + 1, 1);

    double DivideBy(uint count){
        const double shift = 4.0 * 1024 * 1024 * 1024;

        double rtn       = 0;
        long   remainder = 0;

            rtn *= shift;
            remainder <<= 32;

        rtn += remainder / (double)count;

        return rtn;









For those interested, my test code is below:

        yield return i;

static void Test(){
    Console.BufferHeight = 1200;
    Random rnd = new Random();

            numbers[j] = (uint)rnd.Next();

        double sum = 0;
        foreach(uint n in numbers)
            sum += n;

        double avg = sum / numbers.Length;


        if(avg != ans)

        uint upperbound = lowerbound + length;



        if(avg != ans)
share|improve this answer
add comment

Your Answer


