【问题标题】:C++11 std::to_string(double) - No trailing zerosC++11 std::to_string(double) - 没有尾随零
【发布时间】:2012-11-21 02:37:46
【问题描述】:

今天试用了C++11 STL的一些新功能,遇到std::to_string

可爱,可爱的一组功能。为一个双字符串转换创建一个字符串流对象对我来说总是有点过头了,所以我很高兴我们现在可以做这样的事情:

std::cout << std::to_string(0.33) << std::endl;

结果?

0.330000

我对此并不完全满意。有没有办法告诉std::to_string 省略尾随零?我搜索了互联网,但据我所知,该函数只接受一个参数(要转换的值)。回到使用字符串流的“过去”,您可以设置流的宽度,但我宁愿不转换回来。

之前有人遇到过这个问题/有解决方案吗?一些 StackOverflow 搜索结果一无所获。

(C++11 STL 参考:http://en.cppreference.com/w/cpp/string/basic_string/to_string

【问题讨论】:

  • @chris:不是在致电std::to_string 之后。它返回一个字符串,而不是一个数字,而且它的格式似乎很难修改。
  • @rubenvb,射击,我的想法不对,是不是……
  • “可爱的,可爱的一组函数。创建一个字符串流对象只用于一次双字符串转换对我来说总是有点过分”。然后你就会明白为什么它不是真的矫枉过正——它是包含所有用于指定格式的基础设施的流。为了得到你想要的,to_string 必须在一个等效的 API 中复制所有这些。这可能不是一个糟糕的想法,但这不是委员会的想法。 to_string 之所以可爱,是因为它没有选项 ;-)
  • @Steve:是的,我可以看到它们来自哪里。我宁愿 to_string(double/float) 默认不附加任何尾随零,如果需要的话让你使用字符串流。但这涉及到偏好问题。
  • @Frishert:是的。我将这些功能视为快速而肮脏的输出器,用于记录或输出打算由机器使用。不幸的是,对于漂亮的格式,您通常必须自己动手。

标签: c++ stl c++11


【解决方案1】:

如果您只想删除尾随零,那很简单。

std::string str = std::to_string (f);
str.erase ( str.find_last_not_of('0') + 1, std::string::npos );

【讨论】:

  • 工作几乎完美,除了浮点数/双精度数是整数的极端情况。结果是例如440.,而有些人可能更喜欢440.0,如果他们想要获得漂亮的输出。不过,没有什么是简单检查最后一个字符无法解决的问题。
  • 正确,这就是我调整 Marshalls 代码的原因:namespace util { template &lt;typename T&gt; std::string to_string(const T&amp; t) { std::string str{std::to_string (t)}; int offset{1}; if (str.find_last_not_of('0') == str.find('.')) { offset = 0; } str.erase(str.find_last_not_of('0') + offset, std::string::npos); return str; } } 这也删除了一个不必要的点。
  • 使用 . 重复最后一次擦除足以删除尾随句点 str.erase ( str.find_last_not_of('0') + 1, std::string::npos ); str.erase ( str.find_last_not_of('.') + 1, std::string::npos );
  • 是的,@ZacharyCanann 说了什么!我最终得到了很多带有“。”的数字。最后:)
【解决方案2】:

C++11 标准明确表示 (21.5/7):

返回:每个函数返回一个字符串对象,该对象保存其参数值的字符表示形式,该参数值将通过使用格式说明符“%d”、“%u”调用 sprintf(buf, fmt, val) 生成,分别为“%ld”、“%lu”、“%lld”、“%llu”、“%f”、“%f”或“%Lf”,其中 buf 指定足够大小的内部字符缓冲区

对于按此顺序声明的函数:

string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);

因此,您无法控制结果字符串的格式。

【讨论】:

    【解决方案3】:

    std::to_string 让您无法控制格式;您会得到与 sprintf 相同的结果,并为类型使用适当的格式说明符(在本例中为 "%f")。

    如果您需要更大的灵活性,那么您将需要更灵活的格式化程序 - 例如std::stringstream

    【讨论】:

    • 好的,这显然不是我希望的答案,但感谢您解决这个问题:)
    【解决方案4】:

    省略尾随零:

    std::ostringstream oss;
    oss << std::setprecision(8) << std::noshowpoint << double_value;
    std::string str = oss.str();
    

    注意:#include &lt;sstream&gt;#include &lt;iomanip&gt;

    【讨论】:

    • 我不明白为什么这个anwser不是顶级的!谢谢伊万
    【解决方案5】:

    std::to_string(double) 被标准定义为只返回与sprintf(buf, "%f", value) 生成的相同的字符序列。不多也不少,尤其是无法调整格式说明符。所以不,你无能为力。

    【讨论】:

      【解决方案6】:

      使用boost::to_string,您也无法控制格式,但它会输出更接近您在屏幕上看到的内容。与std::lexical_cast&lt;std::string&gt; 相同。

      对于带有格式控制的类似函数的操作,请使用str(boost::format("...format...")% 0.33)

      What's the difference between std::to_string, boost::to_string, and boost::lexical_cast<std::string>?

      【讨论】:

        【解决方案7】:

        由于to_string 不起作用,因此该问题的多种解决方案不起作用。 “魔方”——我的 CS2400 老师

        std::cout.setf(ios::fixed);
        std::cout.setf(ios::showpoint);
        std::cout.precision(2);
        
        const double x = 0.33, y = 42.3748;
        std::cout << "$" << x << std::endl;
        std::cout << "$" << y << std::endl;
        

        输出:

        $0.33
        $42.37
        

        您使用十进制数字执行的任何以下输出都将被设置为这样。

        您始终可以根据需要更改 setf 和精度。

        【讨论】:

          【解决方案8】:

          创建自定义转换函数,如有必要,删除拖尾零。

          //! 2018.05.14 13:19:20 CST
          #include <string>
          #include <sstream>
          #include <iostream>
          using namespace std;
          
          //! Create a custom convert function, remove the tailing zeros if necessary.  
          template<typename T>
          std::string tostring(const T &n) {
              std::ostringstream oss;
              oss << n;
              string s =  oss.str();
              int dotpos = s.find_first_of('.');
              if(dotpos!=std::string::npos){
                  int ipos = s.size()-1;
                  while(s[ipos]=='0' && ipos>dotpos){
                      --ipos;
                  }
                  s.erase ( ipos + 1, std::string::npos );
              }
              return s;
          }
          
          int main(){
              std::cout<< tostring(1230)<<endl;
              std::cout<< tostring(12.30)<<endl;
          }
          

          输入数字:

          1230
          12.30
          

          -std=c++11编译,那么结果:

          1230
          12.3
          

          【讨论】:

            【解决方案9】:

            编写一个通用辅助函数,如下所示,您可以将其重新用于 C++ 项目中的舍入需求。

            inline static const string roundDouble(const double input, const int decimal_places)
            {
                ostringstream str;
                str << fixed << setprecision(decimal_places);
                str << input;
                return str.str();
            }
            

            【讨论】:

              【解决方案10】:
              double val
              std::wstringstream wss;
              wss << val;
              cout << wss.str().c_str();
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2012-07-02
                • 1970-01-01
                • 1970-01-01
                • 2015-06-16
                • 2017-12-29
                • 2013-11-22
                • 2013-02-18
                相关资源
                最近更新 更多