[嵌入式RTOS]记录一下因浮点数转为字符串导致精度损失所踩的坑

1.起因:

工作中对接平台需要将设备的GPS数据传给平台,但是平台采用的不是回调函数将数据直接作为参数返回而是格式化的字符串命令,所以需要将double类型的gps数据格式化输出到字符串中,项目中之前采用的是sprintf进行格式化输出,但是通过打印对比发现有精度损失,所以改成先放大数据1000000倍(数据有6位小数),然后整数部分通过做除法获得,小数部分通过取模运算获得。

void report_gps_info(double lon,double lat)
{
  //some codes
  sprintf(gpsinfo,"%.6lf&%.6lf",lat,lon);
  //some codes
}

void report_gps_info(double lon,double lat)
{
  //some codes
  UINT32 enlarged_lat = lat*1000000;   //added by xxx to solve the problem of loss of accuracy
  UINT32 enlarged_lon = lon*1000000;
  sprintf(baseinfo,"%d.%d&%d.%d",enlarged_lat/1000000,enlarged_lat%1000000,enlarged_lon/1000000,enlarged_lon%1000000);
  //some codes
}

2.再次出问题:

修改后当时测试还是有精度损失,不过只在最后一位差了1影响微乎其微就没怎么在意,于是提交了代码,merge后隔了几天分公司同事测试发现地图上位置出现了很大偏移,查看log发现是数据经过这个函数处理后出的问题,只有经度错误,纬度数据正常,对比查看发现原因是经度数据小数第一位为0,乘1000000后取模让前面的0出现了丢失导致的。

3.最终解决方案:

最终在取模结果也就是小数部分的格式控制上加了位宽限制解决了问题。

void report_gps_info(double lon,double lat)
{
  //some codes
  UINT32 enlarged_lat = lat*1000000;   //added by xxx to solve the problem of loss of accuracy
  UINT32 enlarged_lon = lon*1000000;
  sprintf(baseinfo,"%d.06%d&%d.06%d",enlarged_lat/1000000,enlarged_lat%1000000,enlarged_lon/1000000,enlarged_lon%1000000);
  //some codes
}
1、%d 普通的整数输出
2、%6d 整数输出,宽度是6位,不足左边补空格
3、%06d 整数输出,宽度是6位,不足左边补数字0
4、%-6d 整数输出,宽度是6位,不足右边补空格
5、%.6f 输出小数,即保留小数点后6位

4.反思:

当时提交代码前测试所处位置的gps数据小数位第一位正好不为0就没注意到这个问题,考虑问题真的不够全面。。。在处理这种数据问题时应该更严谨和考虑更多种情况的,突然又想起上次改动最小系统进行OTA升级代码时没有加宏控,从而导致在升级时调用非最小系统代码让系统卡死的事,也是因为考虑问题不全面,自测流程也不完整导致的。将这些经历记录于此,希望以后不再踩此类的坑。

热门相关:帝少的专属:小甜心,太缠人   网游之逆天飞扬   网游之逆天飞扬   明月照大江   天启预报