【问题标题】:C++: what is the optimal way to convert a double to a string?C ++:将双精度转换为字符串的最佳方法是什么?
【发布时间】:2009-08-21 20:11:19
【问题描述】:

实现这一目标的最最佳方法是什么?

void foo(double floatValue, char* stringResult)
{
    sprintf(stringResult, "%f", floatValue);
}

【问题讨论】:

  • 你必须小心你指定的API,因为你正在写入一个你不知道大小的缓冲区,所以你不能保证上面代码的安全性。
  • C 和 C++ 在这方面是不同的,所以你的问题应该是其中之一......
  • 定义最优。您想要最快的执行时间、最低的内存使用率、最安全的操作、最易读的代码,还是别的什么?在明确这一点之前,您将获得非常广泛的答案。
  • 我赞同 TheUndeadFish 的评论。您是否要求最快的执行时间?
  • 下面的一些例子怎么样:codeproject.com/KB/recipes/Tokenizer.aspx它们非常高效,而且有点优雅。

标签: c++ c


【解决方案1】:

我相信有人会说 boost::lexical_cast,所以如果你使用 boost,那就去吧,但无论如何它基本上是一样的:

 #include <sstream>
 #include <string>

 std::string doubleToString(double d)
 {
    std::ostringstream ss;
    ss << d;
    return ss.str();
 }

请注意,您可以轻松地将其制作成一个模板,该模板适用于任何可以流式插入(不仅仅是双打)的东西。

【讨论】:

  • 我应该注意到,由于提出问题的方式(从 C 到 C++),我将“最佳”解释为“最惯用的”而不是“最快的执行”。跨度>
  • 关于此方法的执行时间,请参见:stackoverflow.com/questions/1250795/…
  • 更好:使用模板来处理任意数量的类型,因此您不必为每次转换编写实现。
  • 这与执行时间的“最佳”相反。它为初学者分配内存。
【解决方案2】:

http://www.cplusplus.com/reference/iostream/stringstream/

double d=123.456;
stringstream s;
s << d; // insert d into s

【讨论】:

  • 如果你打算使用这种方法(我个人会选择 boost::lexical_cast...),那么我建议使用 istringstream。它可能比字符串流更轻量级,更重要的是,您不能以错误的方式获得“
【解决方案3】:

升压::lexical_cast

【讨论】:

    【解决方案4】:

    在 dinkumware STL 上,字符串流由 C 库 snprintf 填充。

    因此直接使用 snprintf 格式化将与 STL 格式化部分相媲美。 但有人曾经告诉我,整体大于或等于已知部分的总和。

    由于 stringstream 是否会进行分配将取决于平台(我很确定 DINKUMWARE 还没有在 stringstream 中包含一个小缓冲区来转换像你这样的单个项目),任何需要的东西都是值得怀疑的分配(特别是如果 MULTITHREADED)可以与 snprintf 竞争。

    事实上(格式化+分配)作为分配有可能非常糟糕,除非分配实现具有线程本地小堆,否则在多线程环境中发布很可能需要 2 个完整的读取-修改-写入周期。

    话虽如此,如果我真的关心性能,我会听取上述其他一些 cmets 的建议,更改界面以包含大小并使用 snprintf - 即

    bool 
    foo(const double d, char* const p, const size_t n){
         use snprintf......
         determine if it fit, etc etc etc.
    }
    

    如果你想要一个 std::string,你最好还是使用上面的方法并从结果 char* 实例化字符串,因为 std::stringstream、std::string 解决方案将涉及 2 个分配 + 2 个版本.

    顺便说一句,我无法判断问题中的“字符串”是 std::string 还是“字符串”的通用 ascii 字符用法

    【讨论】:

    • BTW snprintf 对于 uint32 来说是手工编码的 uitoa 的大约 10 倍。我已经做了很多工作,我们以接近 1mm mps 的速率发布 ascii 数字数据(受协议约束,但由于是二进制)。不使用 snprintf 是一个巨大的胜利 - 考虑一下 - 分支预测,格式字符串的额外解析以及必须处理所有不同的可能格式 - 哎哟!
    【解决方案5】:

    最好的办法是构建一个简单的模板化函数来将任何可流式传输的类型转换为字符串。这是我的做法:

    #include <sstream>
    #include <string>
    
    template <typename T>
    const std::string to_string(const T& data)
    {
       std::ostringstream conv;
       conv << data;
       return conv.str();
    }
    

    如果你想要一个 const char* 表示,只需在上面替换 conv.str().c_str()。

    【讨论】:

    • 只有在您无权使用 boost 时才这样做。如果您无法获得提升,请开始尝试获得它! :)
    • 你基本上已经写好了 boost::lexical_cast! :) 干净、优雅且非常慢(因为 IO 流很慢)。
    • 不要将conv.str() 替换为conv.str().c_str()。然后您将返回一个指向立即超出范围的局部变量的指针!
    【解决方案6】:

    我可能会同意您在问题中的建议,因为没有内置的 ftoa() 函数,并且 sprintf 可以让您控制格式。谷歌搜索“ftoa asm”会产生一些可能有用的结果,但我不确定你想走那么远。

    【讨论】:

      【解决方案7】:

      我想说sprintf 几乎是最佳方式。您可能更喜欢snprintf,但它与性能没有太大关系。

      【讨论】:

      • 由于 printf 系列函数必须在运行时解析格式化字符串,因此应该有一种更快的方法,不必这样做。
      • 没错,但由于 printf 的底层部分没有公开可用的入口点,唯一的方法是自己编写(这会重复代码并因此增加加载时间! ;-)) 或忽略解析格式化字符串的性能损失。您不能认真对待解析 2(两个!)字符(嗯,包括 NUL 在内的 3 个)对性能的影响,可以吗?
      【解决方案8】:

      Herb Sutter 对将 int 转换为字符串的替代方案进行了广泛的研究,但我认为他的论点也适用于双精度数。

      他着眼于模板中安全性、效率、代码清晰度和可用性之间的平衡。

      在这里阅读:http://www.gotw.ca/publications/mill19.htm

      【讨论】:

        【解决方案9】:

        _gcvt_gcvt_s

        【讨论】:

          【解决方案10】:

          如果你使用 Qt4 框架,你可以去:

          double d = 5.5;
          QString num = QString::number(d);
          

          【讨论】:

            【解决方案11】:

            这是一个非常有用的线程。我使用 sprintf_s ,但我开始怀疑它是否真的比其他方式更快。我在 Boost 网站上看到了以下文档,该文档显示了 Printf/scanf、StringStream 和 Boost 之间的性能比较。

            Double 到 String 是我们在代码中进行的最常见的转换,所以我会坚持我一直在使用的。但是,在其他情况下使用 Boost 可能是您的决定因素。

            http://www.boost.org/doc/libs/1_58_0/doc/html/boost_lexical_cast/performance.html

            【讨论】:

              【解决方案12】:

              以后可以用std::to_charshttps://godbolt.org/z/cEO4Sd这样的代码。不幸的是,只有 VS2017 和 VS2019 支持此功能的一部分...

              #include <iostream>
              #include <charconv>
              #include <system_error>
              #include <string_view>
              #include <array>
              
              int main()
              {
                  std::array<char, 10> chars;
                  auto [parsed, error] = std::to_chars(
                      chars.data(), 
                      chars.data() + chars.size(), 
                      static_cast<double>(12345.234)
                  );
                  std::cout << std::string_view(chars.data(), parsed - chars.data());
              }
              

              有关 MSVC 详细信息的冗长讨论,请参阅 https://www.reddit.com/r/cpp/comments/a2mpaj/how_to_use_the_newest_c_string_conversion/eazo82q/

              【讨论】:

                猜你喜欢
                • 2019-01-22
                • 1970-01-01
                • 2013-10-10
                • 2015-04-10
                • 1970-01-01
                • 2014-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多