Average four 16 bit numbers in Hi-Tech C

Thread Starter

Guinness1759

Joined Dec 10, 2010
64
Lets say I have temp1, temp2, temp3, and temp4 and they are 16 bit numbers. How do I take the average of them?

I tried

volatile unsigned char temp1[2], temp2[2], temp3[2], temp4[2], ave_temp[2];

ave_temp = (temp1+temp2+temp3+temp4)/4

but it's giving me a bunch of errors.
 

RiJoRI

Joined Aug 15, 2007
536
16 bit numbers are usually ints. An int (16 bits) is NOT the same as two (8-bit) chars.

And if you are adding 4 16-bit ints, you may overflow to the 17th and 18th bits.

You are trying to do (T1+T2+T3+T4)/4. Another -- and in this case better -- way is (T1/4)+(T2/4)+(T3/4)+(T4/4). But unless the numbers are multiples of four you'll have a rounding error.

Adding 2 to each number will round up and give a better -- not precise, but better -- answer.

Work it out on paper. You can use 8- or 4- bit numbers. Remember, dividing by 4 is the same as shifting right twice.

HTH,
--Rich
 

Thread Starter

Guinness1759

Joined Dec 10, 2010
64
edit: thanks. I think I decided that I'm going to send the data out and do processing on the computer side, that way it can keep track of decimals.
 
Last edited:

Papabravo

Joined Feb 24, 2006
21,159
What decimals?

You should do the arithmetic using multi-byte precision operations. If you have a 24-bit accumulator then overflow with 16-bit unsigned ints will be no problem. This is probably beyond your capability if you're willing to give up so easily.
 

THE_RB

Joined Feb 11, 2008
5,438
All you need is a 32bit variable to add the numbers in;

Rich (BB code):
unsigned long math;  // 32bit variable

math = 0;
math += temp1;
math += temp2;
math += temp3;
math += temp4;
math += 2;  // add half the divisor, is compensation for integer rounding
math = (math / 4);
// at this point math is guaranteed <65536 so it is safe to put back
// into a 16bit variable if needed.
 

Alberto

Joined Nov 7, 2008
169
There is a turn around when averaging big numbers that can generate an overflow during addition.

Here the method:

Sort in ascending way all the values

Take the first value (the smallest).

Subtract the first value from all the other values and add together the differences.

Average the sum of the difference.

Add the average to the smallest number you have choosen.

And the result is the same algebric average of the conventional calculation.

Cheers

Alberto
 

THE_RB

Joined Feb 11, 2008
5,438
Interesting method! But what if the smallest sample is 0 and the other 3 samples are 65535? To average the 3 differences you would still need to add 3* 65535 which still overflows the 16bit accumulator...

Another way would be to reduce the resolution of the 4 samples to where they could not overflow a 16bit accumulator when added.

If you divide all the 4 16bit samples by 4 and then add them, the result must still fit in a 16bit accumulator. You can negate the rounding down error by adding 2 to each sample before it is divided by 4, provided every sample is <=65533.

If you need the full range 0-65535 then you could accumulate the bottom 2 bits of each sample in a second accumulator (8bit size) before they are divided by 4 and then apply it later.
 

t06afre

Joined May 11, 2009
5,934
In C we have something named Integral Promotion. It may "kick in" in your case. But it will depend on your C compiler. Also drop the divide operation. As it seams your compiler is struggling with this math operation. Instead use the Right shift (>>) operator. The value of a right-shift expression x >> y is x / (2^y). So a divide by 4 is easy to do. And the shift operator is part of the backbone functions in any C compiler
When there is more than one operand to an operator, they typically must be of exactly the same type. The compiler will automatically convert the operands, if necessary, so they have the same type. The conversion is to a “larger” type so there is no loss of information. Even if the operands have the same type, in some situations they are converted to a different type before the operation. This conversion is called integral promotion. The compiler performs these integral promotions where required. If you are not aware that the type has changed, the results of some expressions are not what would normally be expected. Integral promotion is the implicit conversion of enumerated types, signed or unsigned varieties of char, short int or bit-field types to either signed int or unsigned int. If the result of the conversion can be represented by an signed int, then that is the destination type, otherwise the conversion is to unsigned int.
 
Last edited:
Top