Boost logo

Boost Users :

From: Samuel Krempp (krempp_at_[hidden])
Date: 2004-04-23 06:22:56


On Wed, 2004-04-14 at 21:11, Navneet Dalal wrote:
> Hi
>
> I decided to try boost::format for more compact and typesafe formatting of
> text. However, I am running into some problems.
>
> Problem 1
> ==============
>
> The following line throws boost:bad_format_string exception.
> std::cout << format("%|1| %|2$3|") % "Hello" % 3 << std::endl;

the exception comes from parsing.hpp:465
( " // dont mix positional with non-positionnal directives ")
The problem is %|1| is a non-positional directive, and even though the
code could assume it should take the first argument, it throws, due to
this rule, rather than trying to be clever.

What you want is :
std::cout << format("%|1$| %|2$3|") % "Hello" % 3 << std::endl;
(or |1$1| if you actually want to make sure the first argument's string
is at least padded to be one char long)

>
> However, this one works
> std::cout << format("%|1|") % "Hello" << std::endl;
>
> All I want to do is use notation for printing character streams i.e. %|1|
> instead of %1%

hmm, not sure what you mean here, but the equivalent to %1% would be
%|1$| (it merely wraps up posix printf notation, minus the final
type-conversion letter)

> Problem 2
> =============
>
> How can I print a float such that it appends 0 for remaining precision digits.
>
> For e.g. let us say I want to print 0.2 with 5 characters of overall length
> and till 3 digits of precision. Kind of output I am looking for is 0.200

what range do you expect the numbers at runtime to lie in ? will they
always be in [0.001, 10 [, for instance ?

If you cant assume anything on the range of numbers, you must be
prepared for all kind of numbers, e.g. 1.002e-34 as well as 1.002e34
For this 'scientific' notation of float numbers (the 'e' printf
conversion, [-]d.dddeħdd), it is easy to specify and control the number
of digits before/after the radix, whatever the number range. But it is
often found ugly to the human eye.

You're talking about number 0.2, and for such a number you usually dont
want to show any exponent.
Then the fixed notation (as many digits necessary, plus radix, plus a
*fixed* number of digits) seems to be what you want, but you have to be
aware that whatever parameters you choose, a fixed conversion formatting
will be unadequate to many numbers, so you should resort to it only when
you know the numbers have to lie in some range.

example :
format("%|05.3f|") % x;
x=0.2 -> "0.200"
x=1.02e-34 -> "0.00"
x=1.02e+34 -> "102000 [..] 000.00" (34 digits plus radix and ".00". Also
some float to integral artifact might kick in to mess up the digits
beyond float precision)

So, if you want to format numbers in a certain range, you might be able
to do what you want with fixed conversion.
( "05.3f" is suitable for numbers in [0.001, 10[ . it will hide the
value for numbers closer to 0, and will begin taking more space if >=10
)

The default conversion (which is 'g', as general) resorts to scientific
when necessary, and use a modified fixed notation otherwise (I say
modified, because the 'precision' parameter meaning is changed)
cf http://www.opengroup.org/onlinepubs/7908799/xsh/fprintf.html :
g,G :
The double argument is converted in the style f or e (or in the style E
in the case of a G conversion character), with the precision specifying
the number of significant digits. If an explicit precision is 0, it is
taken as 1. The style used depends on the value converted;
 style e (or E) will be used only if the exponent resulting from such a
conversion is less than -4 or greater than or equal to the precision.
Trailing zeros are removed from the fractional portion of the result; a
radix character appears only if it is followed by a digit. The fprintf()
family of functions may make available character string representations
for infinity and NaN.

> std::cout << format("#%|1$-05.03|#") % 0.2 << std::endl;
> // however it prints
> #0.2 #
..
> with C++ cout, I can print it like
> std::cout << '#' << std::left << std::setfill('0') << std::setw(5) <<
> std::setprecision(3) << 0.2 << '#' << std::endl;
>
you should not try to hack number conversion this way, on the string
itself, it's a bit like resorting to :
std::cout << "0.200"; :-p
in that it assumes too much on the number being converted..


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net