开发者

stringstream: why does "showpoint" behave similar as "fixed"?

开发者 https://www.devze.com 2023-03-10 12:19 出处:网络
I\'d like to write my own lexical_cast which preserves the decimal point when converting double to std::string. So I\'m using ostringstream and set the flag std::ios::showpoint:

I'd like to write my own lexical_cast which preserves the decimal point when converting double to std::string. So I'm using ostringstream and set the flag std::ios::showpoint:

#include <string>
#include <iostream>
#include <boost/lexical_cast.hpp>

template <typename Source>
std::string my_string_cast(Source arg){
   std::ostringstream interpreter;
   interpreter.precision(std::numeric_limits<Source>::digits10);
   interpreter.setf(std::ios::showpoint);
   interpreter << arg;
   return interpreter.str();
}

int main(int argc, char** argv) {
   std::cout << my_string_cast(1.0) << std::endl;
   std::cout << my_stri开发者_StackOverflowng_cast(5.6) << std::endl;
   std::cout << my_string_cast(1.0/3.0) << std::endl;
   return 0;
}

This, however, prints unnecessary 0 digits, a behaviour I'd expect from setting std::ios::fixed but not std::ios::showpoint:

1.00000000000000
5.60000000000000
0.333333333333333

Without setting std::ios::showpoint it gives

1
5.6
0.333333333333333

but I want something like this:

1.0
5.6
0.333333333333333

Any easy way?


What you are wanting seems like a fairly custom behavior to me.

It may not the best way, but you can output all of the digits to your ostringstream, then search for the last non '0' character in the stream. Set the ending position of you stream to that position.

something along the lines of:

size_t endPos = interpreter.str().find_last_of("0");  
size_t begPos = interpreter.str().find_first_of(".") +2;  
if( endPos < begPos )  
  return interpreter.str().substr(0, begPos);  
else  
  return interpreter.str().substr(0, endPos);  


After a long time looking through the code of the std library it seems everything gets handed over to some printf type function: __builtin_vsnprintf(__out, __size, __fmt, __args). The format string __fmt is set depending on the flags set on the ostringstream object and can be queried using

std::ostringstream s;
// ...
char format[50];
std::__num_base::_S_format_float(s,format,'\0');

The default format string is %.*g which is used as in printf("%.*g",precision,x); where precision is an int and x the double to be printed. For the other flags we get:

s.setf(std::ios::fixed);      // %.*f
s.setf(std::ios::showpoint);  // %#.*g

Yet the format %#g doesn't just keep the decimal point but also keeps all trailing zeros. The doc says about the usage of # combined with g:

"printf" will always print out a decimal point and trailing zeros will not
be removed; usually 'g' and 'G' remove trailing zeros.

Unfortunately, I can't find any other printf format string which behaves as nice as %g but always keeps the decimal point, so I guess something along the lines of dschaeffer's answer might well be the best.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号