2

Say you have something like:

std::ostringstream oss;
int value(42);
oss.fill('0');
oss << std::setw(3) << value;
cout << oss.str();

OUTPUT: 042

This output is because std::setw ensures a minimum width and we told the stream to fill with 0 however how do you do the opposite and specify a maximum width so that display will be truncated in STL and native C++ preferably ...

Currently I have something which I consider an ugly and inefficient hack:

std::ostringstream oss;
int value(1239999);
oss.fill('0');
oss << std::setw(3) << boost::lexical_cast<std::string, int>(value).substr(0, 3);
cout << oss.str();

OUTPUT: 123

I've looked at boost::format but it's the same story there as far as I can tell there is no way to do this "prettily" ... any suggestions?

UPDATE: std::ostringstream and STL streams in general are known to perform slowly compared to other containers and template objects of STL. Perhaps I would be better off making a message queue object which wraps and internally uses a std::queue and then just use sprintf_s for formatting purposes?

AJG85
  • 15,849
  • 13
  • 42
  • 50
  • How on earth can it be correct that `"123"` is a correct representation of both `123` and `1239999`? If this is true I don't think you really have integers at all. – SingleNegationElimination Dec 15 '10 at 22:38
  • this is a simple representation out of context to make the problem clear ... in actual use the value represents fractional seconds of a posix time object being logged as part of a timestamp for the entry which is inaccurate past 3 digits on most operating systems, wastes space, and makes the log harder to read. – AJG85 Dec 17 '10 at 15:37

2 Answers2

3

Truncating to remove significant digits is "frowned upon" by most modern programmers. In the bad old days of FORTRAN formatting, it was pretty common to get output like

Total Sales
-----------
9,314,832.36
1,700,328.04
*,***,***,**
8,314,159.26
...

Even modern day Excel falls into this trap with its field width overflow indication of ########

If the number being output does not fit into the field width, the current philosophy is to break the boundaries of the field width and reliably show the value. The only disadvantage would be if a FORTRAN program is going to read the input (thus expecting strict column usage).

wallyk
  • 56,922
  • 16
  • 83
  • 148
  • We used to have this problem with COBOL: pass a value through a chain of programs, fail to have enough 9s in the `9(x)V99` in one program, get a plausible-looking bad value. – David Thornley Dec 15 '10 at 22:37
  • The truncation is because the posix time I am using for the logging library is putting fractional seconds out to 6+ digits when windows and most OS clock is only accurate to 1/60th of a second or about 3 digits ... it also saves space in the log. – AJG85 Dec 17 '10 at 15:26
  • If the goal is simply to remove excess precision, then arithmetically remove the extra digits by multiplying by a power of ten, truncating to an integer and dividing by the same power of ten. There's a chance that might not work due to floating point reduced precision, but the string truncation method will work effectively as long as the magnitude of the number is known. – wallyk Dec 17 '10 at 20:59
0

The stream formatting capabilities are not intended as a general purpose string manipulation package. What you are trying to do does not make much sense numerically, so it is not supported - using the substring or similar functions is the way to go. You can (and should, if you need this in more than one place) write your own function to do the job.

Something like:

#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>

void First3( std::ostream & os, int value ) {
    std::ostringstream oss;
    oss.fill('0');
    oss << std::setw(3) << value;
    os << oss.str().substr( 0, 3 );
}

int main() {
    First3( std::cout, 1239999 );
    std::cout << " ";
    First3( std::cout, 1 );
}

Note there is no need for Boost to be used.

unquiet mind
  • 1,082
  • 6
  • 11
  • it's purely for display formatting of fractional seconds in a logging library. It is only used in one place but that place is used heavily which is why I'm concerned about performance of the proposed hack although it hasn't proved problematic yet. boost is already widely used in our apps and in this case itoa is not supported on all platforms so this is better. – AJG85 Dec 17 '10 at 15:28