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

时间:2018-07-10 12:30:59

标签: c++ performance

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

我误读了报告,而瓶颈还在别的地方吗?

配置文件报告状态:

  

总CPU%= 13.02%,自身CPU%.07,总计CPU(ms)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();
}

2 个答案:

答案 0 :(得分:10)

如果可以使用外部库来实现此目标,则可以使用fmtlib(此库可能会成为标准),它声称比其他方法要快(请参见它们的{{3 }}。

#include <fmt/format.h>

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

这将返回与原始函数相同的字符串,并且您不会像使用std::*printf方法那样牺牲类型安全性。相反,使用benchmarks(它们声称比printf系列abseil更快)时,该函数如下所示:

#include <absl/strings/str_format.h>

std::string FloatToScientificString(float val, int width, int precision)
{
    return absl::StrFormat("%*.*e", width, precision, val);
}

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

#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之外的所有代码片段都是类型安全的。

答案 1 :(得分:4)

您应该尝试将比较数据转换为传入的二进制格式,而不是将传入的数据从float转换为char表示形式,使用创建可编译二进制表的工具只能生成一次。

这使您可以将二进制/浮点数与二进制/浮点数进行比较,而无需在运行时进行进一步的介绍。

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