我已经对我的单元测试进行了分析,并且应用程序运行的大部分时间都花费在这部分代码上.它是一个将float转换为字符串的函数.如何重写下面的代码以获得更好的速度性能?
我误读了报告,瓶颈在其他地方吗?
该档案报告指出:
总CPU%= 13.02%,自CPU%.07,总CPU(ms)769,自CPU超出100%769 ms.
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();
}
Run Code Online (Sandbox Code Playgroud)
lub*_*bgr 10
如果使用外部库来实现这一目标是可能的,那么你可以使用fmtlib(这个库可能会成为标准版),声称它比其他方法更快(参见他们的基准测试).
#include <fmt/format.h>
std::string FloatToScientificString(float val, int width, int precision)
{
return fmt::format("{:>{}.{}e}", val, width, precision);
}
Run Code Online (Sandbox Code Playgroud)
这应该返回与原始函数相同的字符串,并且不像处理std::*printf方法那样牺牲类型安全性.当使用abseil时(它们声称明显比这里的printf家族快),该函数看起来像这样:
#include <absl/strings/str_format.h>
std::string FloatToScientificString(float val, int width, int precision)
{
return absl::StrFormat("%*.*e", width, precision, val);
}
Run Code Online (Sandbox Code Playgroud)
还有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);
}
Run Code Online (Sandbox Code Playgroud)
最后,除了标准库之外没有任何外部依赖关系(请注意,使用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);
}
Run Code Online (Sandbox Code Playgroud)
对这些选项的正确性能分析可能是一个独立的主题.但是,这些选项中的任何一个都应该比使用原始方法快得多std::stringstream,并且除了std::snprintf一个类型安全之外的所有片段都是如此.