将浮点数转换为字符串时如何加快此代码的速度?

How to speed up this code when converting float to string?

本文关键字:代码 速度 何加快 转换 浮点数 字符串      更新时间:2023-10-16

我已经分析了我的单元测试,应用程序运行的大部分时间都花在这一段代码上。它是一个将浮点数转换为字符串的函数。如何重写下面的代码以获得更好的速度性能?

我是否误读了报告,瓶颈在其他地方?

配置文件报告指出:

总 CPU 百分比 = 13.02% , 自身 CPU % .07, 总 CPU(毫秒) 769, 自 CPU 输出 的 100% 769 毫秒。

5907个样本中的769个。

std::string FloatToScientificString(float val, int width, int precision)
{
std::stringstream buffer;
buffer << std::scientific << std::setw(width) << std::setprecision(precision) << std::setfill(' ') << val;
return buffer.str();
}

如果使用外部库来实现这个目标,你可以使用 fmtlib(这个库可能会成为标准),它声称比其他方法更快(参见他们的基准)。

#include <fmt/format.h>
std::string FloatToScientificString(float val, int width, int precision)
{
return fmt::format("{:>{}.{}e}", val, width, precision);
}

这应该返回与原始函数相同的字符串,并且您不会像std::*printf方法那样牺牲类型安全性。当使用绳降代替时(他们声称比这里的printf-family快得多),函数看起来像这样:

#include <absl/strings/str_format.h>
std::string FloatToScientificString(float val, int width, int precision)
{
return absl::StrFormat("%*.*e", width, precision, val);
}

还有 boost 格式,它不允许将宽度或精度说明符作为参数传递,但这同样有效:

#include <boost/format.hpp>
std::string FloatToScientificString(float val, int width, int precision)
{
const std::string fmt = "%" + std::to_string(width) + "." +
std::to_string(precision) + "e";
return boost::str(boost::format(fmt) % val);
}

最后,除了标准库之外没有任何外部依赖项(请注意,使用std::snprintf优于std::sprintf,因为会检查缓冲区大小,但这两个函数都不是类型安全的):

#include <cstdio>
std::string FloatToScientificString(float val, int width, int precision)
{
static const int bufSize = 100;
static char buffer[bufSize];
std::snprintf(buffer, bufSize, "%*.*e", width, precision, val);
return std::string(buffer);
}

对这些选项进行正确的性能分析可能本身就是一个主题。但是,这些选项中的任何一个都应该比使用std::stringstream的原始方法快得多,并且除了std::snprintf代码片段之外的所有代码片段都是类型安全的。

与其将传入数据从 float 转换为 char 表示形式,不如尝试将比较数据生成为传入的二进制格式,也许只使用创建可编译二进制表的工具生成一次。

这使您能够将二进制/浮点数与二进制/浮点数数据进行比较,而无需在运行时进行进一步的转换。

您还可以进行测试,将传入的数据记录到某个存储中,然后再次与该存储进行比较。因此,您只比较一次字符串表示形式,然后再与二进制存储的数据进行比较。只要您的测试用例保持不变,就可以完成此操作。