如何在将浮点数转换为字符串时加速代码?

12

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

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

配置文件报告如下:

Total CPU % = 13.02%,Self CPU % .07,Total CPU(ms) 769,Self CPU 占总时间的百分比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
我想当我们调整当前解决方案时,格式应该保持不变,对吗? - lubgr
6
将浮点数转换为字符串是一项复杂的操作,而C++流格式化程序并不是特别轻量级的代码。也许你可以尝试使用C格式化程序(sprintf(buf, "%*.*e", width, precision, val))来加快速度。 - Serge Ballesta
6
你真的需要将它转换为字符串吗?你获得字符串后会用它做什么? - NathanOliver
4
"我已经对我的单元测试进行了分析" - 为什么?运行单元测试需要很长时间吗?如果不是,那就不用担心。 - Martin Bonner supports Monica
3
如果你想要提高开发效率,可以考虑使用类似于“持续集成”的工具以及支持工具,例如远程构建服务器。你可以尝试使用 travis-ci.org,它可以帮助你自动化构建和测试,并且甚至能够创建可部署的包。不必每次构建项目或提交源代码仓库时都运行单元测试,每天运行一次可能就足够了。 - Some programmer dude
显示剩余10条评论
2个回答

10
如果可以使用外部库来实现此目标,则可以选择 fmtlib(该库可能会进入标准库),它声称比其他方法更快(请参见其基准测试)。
#include <fmt/format.h>

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

这应该返回一个与您原来的函数完全相同的字符串,并且与 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);
}

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

#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
@NoSenseEtAl,它基于Python的string::format;无论好坏如何,它已经被广泛地实际使用了。对于简单的用例,语法非常简单。 - Cubic

4

不要将传入的数据从浮点数转换为字符表示形式,而是应该尝试生成与传入二进制格式相对应的比较数据,可以使用一个工具仅生成一次可编译的二进制表格。

这样可以在运行时无需进行进一步的转换,就能够比较二进制/浮点数与二进制/浮点数数据。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接