前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >日更系列之c++的to_string的浮点数精度问题

日更系列之c++的to_string的浮点数精度问题

原创
作者头像
mariolu
发布2022-03-05 19:08:22
2.5K0
发布2022-03-05 19:08:22
举报

一、背景

做了一个根据搜索词计算embedding向量的服务,但是算法同学发现新服务打分精度变低了,原来能保存到小数点后16位的,现在打分只有小数点后6位。

二、单精度双精度浮点数

看到这问题,首先怀疑的是double类型数据被强转float类型,导致精度丢失。

float类型大概精度就是到小数点之后6,7位,来做个实验

代码语言:javascript
复制
int main(int argc, char**argv){
   float a = 0.0123456789012;
   std::cout << std::fixed << std::setprecision(16) << a;
   return 0;
}

然后编译运行输出

代码语言:javascript
复制
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
0.0123456791043282

我们发现这个输出已经跟原来的a不一样了,后面81043282是垃圾数据。

其实计算机对float的编码类型,精度没那么高,double能提供的52 位有效位、11 位指数和 1 位符号位。

参考这个帖子https://stackoverflow.com/questions/5098558/float-vs-double-precision。

但我再仔细对了上下游文件使用的pb,发现这个打分使用的是double类型。所以理论上这个double应该没有类型转换丢失问题。

三、to_string的默认输出精度

这个看起来不应该是类型转换的问题。然后仔细又观察了这段代码。

代码语言:javascript
复制
context->m_query_embedding+=to_string(recommend_info->vecitem(0).vecscore(i));

于是我把这个recommend_info->vecitem(0).vecscore(i)打印出来,这个数据精度是小数点后16位没问题,但是context->m_query_embedding是小数点后6问题。显然是这个std::to_string出现了精读丢失的问题。

果不其然,谷歌搜索到了这个帖子,https://stackoverflow.com/questions/16605967/set-precision-of-stdto-string-when-converting-floating-point-values

谈到to_stiring默认设置精度为6位,如果需要更高精度需要这样设置。

代码语言:javascript
复制
#include <sstream>

template <typename T>
std::string to_string_with_precision(const T a_value, const int n = 6)
{
    std::ostringstream out;
    out.precision(n);
    out << std::fixed << a_value;
    return out.str();
}

当然这里考虑到std提供的ostringstream在多线程环境下性能不如snprintf,

std::stringstream是类型安全的,使用运算符 <<,使用内部缓冲区,属于C++ 的一部分,性能不如sprintf。而sprintf不是类型安全的,不能使用 c++ 运算符,使用外部缓冲区,它只能用于从 C 继承的 POD 类型,速度很快。

具体参考这个帖子https://stackoverflow.com/questions/11574391/snprintf-vs-stdstringstream

于是对这个代码做了如下改写。

代码语言:javascript
复制
char query_embedding_with_high_precision[20];
snprintf(query_embedding_with_high_precision, 20, "%.16f", query_embedding_with_high_precision);
context->m_query_embedding += std::string(query_embedding_with_high_precision);

问题至此解决了,做到了同时保留精度和保持性能

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景
  • 二、单精度双精度浮点数
  • 三、to_string的默认输出精度
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档