c中的平均值,不超过值数据类型



如上所述,如何在不将所有值相加到浮点值的情况下对一个值数组求平均值,这是为了在8位/16位的micro中使用,以缓解时间紧张的浮点值。我已经想出了一个方法,但我担心它比将所有内容添加到浮点数并进行除法更麻烦。我将在下面附上代码。

平均值减少为ADC样本阵列中的第一个元素

平均值.c

#include <xc.h>
#include "Average.h"
#include "Initialize.h"
/*
(x+y)=((x&y)*2)+(x^y)
(x+y)/2=(x&y)+((x^y)>>1)
Does not overflow data type when done in pairs
* No need for floats
* array must have 2/4/8/16/32...values to be averaged
* Accurate rounding
*/
void Average(void)
{
x=0;
for (x=0; x<ADCsamplesize; ++x)
{
ADCsamples[x].value=ADCsampleraw[x];
ADCsamples[x].upflag=0;
}

x=0;
y=0;
z=ADCsamplesize/2;

while(z!=0)
{   
if (((ADCsamples[y].value&0x01)^(ADCsamples[y+1].value&0x01))==1)       //is rounding needed? (even/odd mismatch)
{
if((ADCsamples[y].upflag^ADCsamples[y+1].upflag)==1)                //if ONE has been rounded before
{
if (ADCsamples[y].upflag==1)                                //which to round down?
{
ADCsamples[y].value--;                               
ADCsamples[y].upflag=0;
}
else
{
ADCsamples[y+1].value--;
ADCsamples[y+1].upflag=0;
}
}
else                                                                //round up
{
if (ADCsamples[y].value!=65535)                                 //overflow protection
{
ADCsamples[y].value++;                                         
}
else
{
ADCsamples[y+1].value++;                                    //in the event of a mismatch y and y+1 cannot both be data type max
}
ADCsamples[x].upflag=1;                                         //mark as being rounded up
}
}
else
{
ADCsamples[x].upflag=0;                                            //as elements are reused, clear rounded flag
}

ADCsamples[x].value=(ADCsamples[y].value&ADCsamples[y+1].value)+((ADCsamples[y].value^ADCsamples[y+1].value)>>1); //bitwise average of 2 values, not possible to overflow

if (x+1!=z)                                                             
{
x++;
y=y+2;
}
else
{
z=z>>1;
x=0;
y=0;
}        
}   
} 

平均值.h

#ifndef AVERAGE_H
#define AVERAGE_H
#include <xc.h> // include processor files - each processor file is guarded.  
#ifdef  __cplusplus
extern "C" {
#endif /* __cplusplus */
unsigned char z;
unsigned char x;
unsigned char y;
unsigned char const ADCsamplesize=8;
unsigned int ADCsampleraw[]=
{
123,516,4569,3521,852,456,981,852
};
typedef struct sample{
unsigned int value;
unsigned int upflag;
}sample;
sample ADCsamples[8];

void Average(void);

#ifdef  __cplusplus
}
#endif /* __cplusplus */
#endif  /* XC_HEADER_TEMPLATE_H */

这旨在用于8位/16位的micro中,以减轻时间紧张的浮动。

IMO,OP通过限制";平均值。。。而不超过值数据类型";。

对于小型micro,将值相加为两倍于样本宽度的整数类型,然后进行除法运算。


如果仍然希望在没有更宽类型和溢出的情况下进行平均,下面的操作即可。

// (n-1)*(n-1) should be <= UINT_MAX
int average_unsigned(unsigned n, const unsigned a[]) {
if (n <= 0) {
return 0;
}
unsigned partial = 0;
unsigned residue = 0;
for (unsigned i = 0; i < n; i++) {
partial += a[i] / n; // If n is a true constant and power-of-2, 
residue += a[i] % n; //   these 2 steps are fast   ***
}
return partial + residue / n;
}

***如果n是运行时变量,但仍然是2的幂,则用>> log2n替换/ n,用& (n-1)替换% n

最新更新