当前位置: 首页 > wzjs >正文

南通营销型网站建设福州网站排名

南通营销型网站建设,福州网站排名,邯郸网站建设哪儿好,有什么好的网站做数学题吗【C语言】通用统计数据结构及其更新函数(最值、变化量、总和、平均数、方差等) 更新以gitee为准: gitee 文章目录 通用统计数据结构更新函数附录:压缩字符串、大小端格式转换压缩字符串浮点数压缩Packed-ASCII字符串 大小端转换什…

【C语言】通用统计数据结构及其更新函数(最值、变化量、总和、平均数、方差等)

更新以gitee为准:
gitee

文章目录

  • 通用统计数据结构
  • 更新函数
  • 附录:压缩字符串、大小端格式转换
    • 压缩字符串
      • 浮点数
      • 压缩Packed-ASCII字符串
    • 大小端转换
      • 什么是大端和小端
      • 数据传输中的大小端
      • 总结
      • 大小端转换函数

通用统计数据结构

为了综合常见的统计数据计算 但又不导入math库、开平方根等耗时算法,可以按如下定义结构:

#define FMIN(a,b) ((a) < (b) ? (a) : (b))
#define FMAX(a,b) ((a) > (b) ? (a) : (b))typedef struct
{float sum;int num;float min;float max;float avg;float delta;float m2;       // 二阶中心矩float population_var; // 总体方差float sample_var;      // 样本方差
} StatResultType;

如果需要计算标准差,则通过方差求平方根来求解
大小比较通过宏来实现

更新函数

满足该更新函数的内容如下:

void UpdateStatResult(StatResultType* res, float new_val)
{if(res->num++ == 0){res->min = res->max = new_val;res->sum = new_val;res->avg = new_val;res->delta = 0;res->m2 = 0;res->sample_var = 0;  // 初始化为0res->population_var = 0;return;}// 极值比较res->min = FMIN(res->min, new_val);res->max = FMAX(res->max, new_val);// 增量更新(Welford算法)const float delta = new_val - res->avg;res->sum += new_val;const float new_avg = res->avg + delta / res->num;const float delta2 = new_val - new_avg;res->m2 += delta * delta2;res->avg = new_avg;// 计算衍生统计量res->delta = res->max - res->min;const uint32_t n = res->num;if(n > 1){res->population_var = res->m2 / n;res->sample_var = res->m2 / (n - 1);}else{res->population_var = res->sample_var = 0;}
}

附录:压缩字符串、大小端格式转换

压缩字符串

首先HART数据格式如下:
在这里插入图片描述
在这里插入图片描述
重点就是浮点数和字符串类型
Latin-1就不说了 基本用不到

浮点数

浮点数里面 如 0x40 80 00 00表示4.0f

在HART协议里面 浮点数是按大端格式发送的 就是高位先发送 低位后发送

发送出来的数组为:40,80,00,00

但在C语言对浮点数的存储中 是按小端格式来存储的 也就是40在高位 00在低位
浮点数:4.0f
地址0x1000对应00
地址0x1001对应00
地址0x1002对应80
地址0x1003对应40

若直接使用memcpy函数 则需要进行大小端转换 否则会存储为:
地址0x1000对应40
地址0x1001对应80
地址0x1002对应00
地址0x1003对应00

大小端转换:

void swap32(void * p)
{uint32_t *ptr=p;uint32_t x = *ptr;x = (x << 16) | (x >> 16);x = ((x & 0x00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF);*ptr=x;
}

压缩Packed-ASCII字符串

本质上是将原本的ASCII的最高2位去掉 然后拼接起来 比如空格(0x20)
四个空格拼接后就成了
1000 0010 0000 1000 0010 0000
十六进制:82 08 20
对了一下表 0x20之前的识别不了
也就是只能识别0x20-0x5F的ASCII表
在这里插入图片描述

压缩/解压函数后面再写:

//传入的字符串和数字必须提前声明 且字符串大小至少为str_len 数组大小至少为str_len%4*3 str_len必须为4的倍数
uint8_t Trans_ASCII_to_Pack(uint8_t * str,uint8_t * buf,const uint8_t str_len)
{if(str_len%4){return 0;}uint8_t i=0;memset(buf,0,str_len/4*3);	  for(i=0;i<str_len;i++){if(str[i]==0x00){str[i]=0x20;}}for(i=0;i<str_len/4;i++){buf[3*i]=(str[4*i]<<2)|((str[4*i+1]>>4)&0x03);buf[3*i+1]=(str[4*i+1]<<4)|((str[4*i+2]>>2)&0x0F);buf[3*i+2]=(str[4*i+2]<<6)|(str[4*i+3]&0x3F);}return 1;
}//传入的字符串和数字必须提前声明 且字符串大小至少为str_len 数组大小至少为str_len%4*3 str_len必须为4的倍数
uint8_t Trans_Pack_to_ASCII(uint8_t * str,uint8_t * buf,const uint8_t str_len)
{if(str_len%4){return 0;}uint8_t i=0;memset(str,0,str_len);for(i=0;i<str_len/4;i++){str[4*i]=(buf[3*i]>>2)&0x3F;str[4*i+1]=((buf[3*i]<<4)&0x30)|(buf[3*i+1]>>4);str[4*i+2]=((buf[3*i+1]<<2)&0x3C)|(buf[3*i+2]>>6);str[4*i+3]=buf[3*i+2]&0x3F;}return 1;
}

大小端转换

在串口等数据解析中 难免遇到大小端格式问题

什么是大端和小端

所谓的大端模式,就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

所谓的小端模式,就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

简单来说:大端——高尾端,小端——低尾端

举个例子,比如数字 0x12 34 56 78在内存中的表示形式为:

1)大端模式:

低地址 -----------------> 高地址

0x12 | 0x34 | 0x56 | 0x78

2)小端模式:

低地址 ------------------> 高地址

0x78 | 0x56 | 0x34 | 0x12

可见,大端模式和字符串的存储模式类似。

数据传输中的大小端

比如地址位、起止位一般都是大端格式
如:
起始位:0x520A
则发送的buf应为{0x52,0x0A}

而数据位一般是小端格式(单字节无大小端之分)
如:
一个16位的数据发送出来为{0x52,0x0A}
则对应的uint16_t类型数为: 0x0A52

而对于浮点数4.0f 转为32位应是:
40 80 00 00

以大端存储来说 发送出来的buf就是依次发送 40 80 00 00

以小端存储来说 则发送 00 00 80 40

由于memcpy等函数 是按字节地址进行复制 其复制的格式为小端格式 所以当数据为小端存储时 不用进行大小端转换
如:

uint32_t dat=0;
uint8_t buf[]={0x00,0x00,0x80,0x40};memcpy(&dat,buf,4);float f=0.0f;f=*((float*)&dat); //地址强转printf("%f",f);

或更优解:

   uint8_t buf[]={0x00,0x00,0x80,0x40};   float f=0.0f;memcpy(&f,buf,4);

而对于大端存储的数据(如HART协议数据 全为大端格式) 其复制的格式仍然为小端格式 所以当数据为小端存储时 要进行大小端转换
如:

uint32_t dat=0;
uint8_t buf[]={0x40,0x80,0x00,0x00};memcpy(&dat,buf,4);float f=0.0f;swap32(&dat); //大小端转换f=*((float*)&dat); //地址强转printf("%f",f);

或:

uint8_t buf[]={0x40,0x80,0x00,0x00};memcpy(&dat,buf,4);float f=0.0f;swap32(&f); //大小端转换printf("%f",f);

或更优解:

uint32_t dat=0;
uint8_t buf[]={0x40,0x80,0x00,0x00};float f=0.0f;dat=(buf[0]<<24)|(buf[0]<<16)|(buf[0]<<8)|(buf[0]<<0)f=*((float*)&dat);

总结

固 若数据为小端格式 则可以直接用memcpy函数进行转换 否则通过移位的方式再进行地址强转

对于多位数据 比如同时传两个浮点数 则可以定义结构体之后进行memcpy复制(数据为小端格式)

对于小端数据 直接用memcpy写入即可 若是浮点数 也不用再进行强转

对于大端数据 如果不嫌麻烦 或想使代码更加简洁(但执行效率会降低) 也可以先用memcpy写入结构体之后再调用大小端转换函数 但这里需要注意的是 结构体必须全为无符号整型 浮点型只能在大小端转换写入之后再次强转 若结构体内采用浮点型 则需要强转两次

所以对于大端数据 推荐通过移位的方式来进行赋值 然后再进行个别数的强转 再往通用结构体进行写入

多个不同变量大小的结构体 要主要字节对齐的问题
可以用#pragma pack(1) 使其对齐为1
但会影响效率

大小端转换函数

直接通过对地址的操作来实现 传入的变量为32位的变量
中间变量ptr是传入变量的地址

void swap16(void * p)
{uint16_t *ptr=p;uint16_t x = *ptr;x = (x << 8) | (x >> 8);*ptr=x;
}void swap32(void * p)
{uint32_t *ptr=p;uint32_t x = *ptr;x = (x << 16) | (x >> 16);x = ((x & 0x00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF);*ptr=x;
}void swap64(void * p)
{uint64_t *ptr=p;uint64_t x = *ptr;x = (x << 32) | (x >> 32);x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x >> 16) & 0x0000FFFF0000FFFF);x = ((x & 0x00FF00FF00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF00FF00FF);*ptr=x;
}
http://www.dtcms.com/wzjs/436700.html

相关文章:

  • 找网站公司做网站网站怎么快速排名
  • 动态的网站怎么做上海疫情又要爆发了
  • 美国社交网站 做仿牌杭州seo泽成
  • 街舞舞团公司做网站淘宝指数查询
  • 阿里云网站备案流程百度广告联盟怎么加入
  • 爱妮微如何做网站链接的网址百度云资源搜索引擎
  • 张店网站建设价格拉新app渠道
  • 江苏网站备案暂住证ip反查域名网站
  • 做的网站手机打不开怎么回事啊推广平台app
  • 内外外贸购物网站建设域名信息查询
  • 铜川微网站建设线上推广有哪些渠道
  • 哈尔滨企业网站seo全网线报 实时更新
  • 专业做书画推广的网站网站推广的途径和方法
  • 做徽商要做网站吗手机网页制作软件
  • 东营微信开发网站建设类似58的推广平台有哪些平台
  • 找网站做q币关键词seo是什么
  • 南京做网站建设的公司排名泰安优化关键词排名哪家合适
  • godaddy 网站怎么建设什么是口碑营销
  • vps利用端口做不同网站搜索引擎优化的名词解释
  • 申请学校网站建设申请书友情链接交换网站
  • 陕西西乡网站建设网站免费建站app
  • wordpress开发架构公司网站优化
  • 国内做网站上市公司樱花bt引擎
  • 成品网站源码免费百度游戏中心
  • 白菜博主的返利网站怎么做百度旗下有哪些app
  • 网站做的不好会有什么后果今日最新消息
  • 淘宝优惠网站如何做推广营销是什么
  • 电子商务网站建设分析论文上海seo公司
  • 网站开发读什么专业网络营销学校
  • 做网站 江门域名ip查询