将float转换为字符串时如何加速此代码?

raf*_*lez 12 c++ performance

我已经对我的单元测试进行了分析,并且应用程序运行的大部分时间都花费在这部分代码上.它是一个将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一个类型安全之外的所有片段都是如此.