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

Posted

技术标签:

【中文标题】c中的平均值,不超过值数据类型?【英文标题】:Average values in c, without exceeding value data type? 【发布时间】:2021-03-02 00:09:29 【问题描述】:

如上所述,如何在不将所有值添加到浮点数的情况下对一组值进行平均,这旨在用于 8 位/16 位微控制器,以减轻时间紧迫的浮点数。我想出了一个方法,但我担心它比将所有内容添加到浮点数中并划分更麻烦。我将在下面附上代码。

平均值减少到 ADCsample 数组中的第一个元素

平均.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 */

【问题讨论】:

任一读数的最大值是多少? int 的大小是多少? 您的问题是什么?您想要修复的方法中是否存在错误或问题?你想知道它是否有错误吗?您想要更好还是不同的解决方案? Int 为 16 位,任何读数的最大值可能会填充 16 位,具体取决于 ADC 精度, 问题是这是否通过保持在总线宽度内来减轻 CPU 的压力以及除了暴力添加到对 8/16 位 MCU 来说非常 CPU 密集的浮点数之外还有什么其他方法 以最容易实现并远离浮点的方式编译它。求和为更大的(如有必要)整数类型,然后转移到除法并将实现细节留给编译器。如果吞吐量存在瓶颈,然后寻找更好的解决方案。无论如何,无论是显式地将计算拆分为多个部分,还是隐式地将每个值拆分为多个部分(通过使用更大的类型),您都需要对 CPU 施加压力。 【参考方案1】:

这旨在用于 8 位/16 位微控制器,以缓解时间紧迫的浮点数。

IMO,OP 通过限制“平均值......不超过值数据类型”选择了一个次优解决方案。

对于小型微,将值相加为样本宽度两倍的整数类型,然后除。


如果仍然想在没有更宽类型且没有溢出的情况下进行平均,下面的工作就完成了。

// (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 的幂,请将 / n 替换为 &gt;&gt; log2n 并将 % n 替换为 &amp; (n-1)

【讨论】:

以上是关于c中的平均值,不超过值数据类型?的主要内容,如果未能解决你的问题,请参考以下文章

也谈SQL Server 2008 处理隐式数据类型转换在运行计划中的增强 (续)

C#学习路途之一数据类型中的值类型

每周学习日志

每周学习日志

C和指针之结构体和联合体

SQLite数据类型