function for printing formatted number

W

wang

Hi all
is there a function for converting a number such as 1234567.89 into a
string presentation as "1,234,567.89" for printing? Thanks for any
hints!
kwwang
 
F

Francesco S. Carta

Hi all
is there a function for converting a number such as 1234567.89 into a
string presentation as "1,234,567.89" for printing? Thanks for any
hints!
kwwang

Nothing straight out of the standard C++ box.

Make a search in boost, there could be an appropriate "format" function,
although such a simple function can be created in almost no time. Why
don't you give it a shot and post your code here? You might find that
instructive.
 
Ö

Öö Tiib

is there a function for converting a number such as 1234567.89 into a
string presentation as "1,234,567.89" for printing? Thanks for any
hints!

Such things are in C++ standard library. Hints are such:

class std::locale, template class std::numpunct, template class
std::basic_ios, especially the function imbue().

If you google for these you probably find tons of example code
snippets. I am not sure if they work with MSVC 6.0 however, with 2005
they did work.
 
P

Phlip

Francesco said:
Nothing straight out of the standard C++ box.

This is one of those perennial FAQs that everyone needs and nobody
covers. The locale/facets system in iostreams is apparently a kit for
you to assemble.

The ultimate problem appears to be some undiscovered culture somewhere
might separate hundreds, or ten-thousands, so a locale cannot simply
assume thousands and then ask what delimiter goes there!

http://www.velocityreviews.com/forums/t603778-help-add-commas-to-int-on-console-output.html

#include <sstream>
#include <iostream>
#include <locale>
#include <string>

// custom numeric punctuation facet
struct Punct: std::numpunct<char>
{
char do_thousands_sep () const
{
return ',';
}
std::string do_grouping () const
{
return "\3";
}
};

std::string toStr(int x,std::locale const& l)
{
std::stringstream stream;
stream.imbue(l);

stream << x;
return stream.str();
}


int main()
{
// construct a custom punctuation facet
std::numpunct<char>* punct = new Punct;

// construct a locale containing the custom facet
const std::locale locale(std::cout.getloc(),punct);

std::cout.imbue(locale);
std::cout << "Val: " << 1234556 << std::endl;
std::cout << "From String: " << toStr(123456789,locale) <<
std::endl;
}

That thread then gets the James Kanze treatment, so read his prose to
learn what horrors I just pasted in, untested!
 
F

Francesco S. Carta

This is one of those perennial FAQs that everyone needs and nobody
covers. The locale/facets system in iostreams is apparently a kit for
you to assemble.

The ultimate problem appears to be some undiscovered culture somewhere
might separate hundreds, or ten-thousands, so a locale cannot simply
assume thousands and then ask what delimiter goes there!

http://www.velocityreviews.com/forums/t603778-help-add-commas-to-int-on-console-output.html

#include<sstream>
#include<iostream>
#include<locale>
#include<string>

// custom numeric punctuation facet
struct Punct: std::numpunct<char>
{
char do_thousands_sep () const
{
return ',';
}
std::string do_grouping () const
{
return "\3";
}
};

std::string toStr(int x,std::locale const& l)
{
std::stringstream stream;
stream.imbue(l);

stream<< x;
return stream.str();
}


int main()
{
// construct a custom punctuation facet
std::numpunct<char>* punct = new Punct;

// construct a locale containing the custom facet
const std::locale locale(std::cout.getloc(),punct);

std::cout.imbue(locale);
std::cout<< "Val: "<< 1234556<< std::endl;
std::cout<< "From String: "<< toStr(123456789,locale)<<
std::endl;
}

That thread then gets the James Kanze treatment, so read his prose to
learn what horrors I just pasted in, untested!

All of what you have written was somewhere in the background of my
"Nothing straight out of the standard C++ box" reply.

It's far easier to lookup an ad-hoc function or to write a simple one
instead of delving into the complexity of assembling your own locale,
for such a simple task.

Granted, if one is accustomed to deal with them, one can come up with
something like the above straight from the top of one's head.

As I see it, it just feels like shooting flies with a cannon, with the
further downside that I need to assemble it.
 
O

osmium

Öö Tiib said:
Such things are in C++ standard library. Hints are such:

class std::locale, template class std::numpunct, template class
std::basic_ios, especially the function imbue().

That also answers the question, "Can I learn C++ in 21 days?"
 
Ö

Öö Tiib

All of what you have written was somewhere in the background of my
"Nothing straight out of the standard C++ box" reply.

It's far easier to lookup an ad-hoc function or to write a simple one
instead of delving into the complexity of assembling your own locale,
for such a simple task.

Granted, if one is accustomed to deal with them, one can come up with
something like the above straight from the top of one's head.

As I see it, it just feels like shooting flies with a cannon, with the
further downside that I need to assemble it.

Usually you have that cannon constructed already if you work for shop
that writes C++ for international market. The problem is heavily
localization related. For you "1,234,567.89" is may be natural so you
think it is a "fly" to achieve it. German-speaking nations often like
it other way around, like "1.234.567,89". Some Hindi-speaking guy does
not understand thousand separator, for them there is hundreds
separators. So the solution to have same number readable for all of
them is to have locales, or what else you suggest to do? Hack it ad-
hoc until it is unreadable blob of crap?
 
F

Francesco S. Carta

Usually you have that cannon constructed already if you work for shop
that writes C++ for international market. The problem is heavily
localization related. For you "1,234,567.89" is may be natural so you
think it is a "fly" to achieve it. German-speaking nations often like
it other way around, like "1.234.567,89". Some Hindi-speaking guy does
not understand thousand separator, for them there is hundreds
separators. So the solution to have same number readable for all of
them is to have locales, or what else you suggest to do? Hack it ad-
hoc until it is unreadable blob of crap?

Of course not. Using std::locale or an existing in-house version of them
is the way to go in such cases.

It all depends on the target one wants to achieve.
 
Ö

Öö Tiib

Of course not. Using std::locale or an existing in-house version of them
is the way to go in such cases.

It all depends on the target one wants to achieve.

Yes and target is to format the output *exactly* with all
peculiarities like expected. And these peculiarities are: notation?,
decimal point?, precision?, padding?, thousands or hundreds
separation?, with what separator?, plus sign for positives?,
parentheses around negatives? and so on just name it. Been a bit
around in industry you notice that these damn peculiarities will
change immediately when your bosses sell it not only to neighbour of
yours but few blocks farther too. And then you see how sweet is to
just use locale as a configuration dedicated for next set of poor
fatsos who bought it. There are lot more interesting things to hack
than numeric formats, really.
 
F

Francesco S. Carta

Yes and target is to format the output *exactly* with all
peculiarities like expected.

No, the target was just to format a number following the example given
by the OP. Don't take it for pedantry or for playing word games, all you
are trying to do with me amounts to breaking through an open door: I'll
repeat it, if one needs to take care of all those details, then
std::locale is the way to go, I fully agree with you.

The next time I'll take care of mentioning locales in my replies just to
avoid this kind of discussions, although I'm very well accustomed to see
a question replied by several people from different points of view, to
the advantage of the OP.
And these peculiarities are: notation?,
decimal point?, precision?, padding?, thousands or hundreds
separation?, with what separator?, plus sign for positives?,
parentheses around negatives? and so on just name it. Been a bit
around in industry you notice that these damn peculiarities will
change immediately when your bosses sell it not only to neighbour of
yours but few blocks farther too. And then you see how sweet is to
just use locale as a configuration dedicated for next set of poor
fatsos who bought it. There are lot more interesting things to hack
than numeric formats, really.

Nothing new under my sky, and the same surely stands under yours. But
what about the OP? If one comes here asking for a formatting function,
chances are that one might learn something by hacking numeric formats,
as you pose it.
 
J

Jorgen Grahn

That also answers the question, "Can I learn C++ in 21 days?"

How often do you have to print numbers with ASCII-style thousands
separators? I have never had the need to do it. It's when (a) machine
readability is unimportant, (b) the audience doesn't understand
scientific notation, (c) it's plain text so a half-width nonbreakable
space isn't a better choice. Hasn't happened to me so far, and I
don't think it ever will.

/Jorgen
 
W

wang

No, the target was just to format a number following the example given
by the OP. Don't take it for pedantry or for playing word games, all you
are trying to do with me amounts to breaking through an open door: I'll
repeat it, if one needs to take care of all those details, then
std::locale is the way to go, I fully agree with you.

The next time I'll take care of mentioning locales in my replies just to
avoid this kind of discussions, although I'm very well accustomed to see
a question replied by several people from different points of view, to
the advantage of the OP.


Nothing new under my sky, and the same surely stands under yours. But
what about the OP? If one comes here asking for a formatting function,
chances are that one might learn something by hacking numeric formats,
as you pose it.

--
  FSC -http://userscripts.org/scripts/show/59948
 http://fscode.altervista.org-http://sardinias.com- Zitierten Text ausblenden -

- Zitierten Text anzeigen -

It's interesting to read the whole discussion. But the material is
overwhelming. I've never heard of locale or the like. I feel happy if
I can write code in c++ instead of ANSI C. Before I begin to learn all
these, I prefer to write my own simple function (maybe I should say
method), learning locale etc must be planned for the future.
Here is my code. I use it to format currency amount, which should
contain 2 fraction digits (padded with "0").
kwwang

string bigNumberFormat(double num, short frclen, bool inter)
{
/* num: positive number to be formatted,
frclen: Length of fraction part,
inter: true for international (12,345,678.920), false for German
(12.345.678,920) */
string separator, point;
ostringstream oss;
if (inter) {
separator = ",";
point = ".";
} else {
separator = ".";
point = ",";
}
oss << (long)num;
string tmp, result = "";
tmp = oss.str();
short len = tmp.size(), remainder, repeat;
remainder = len % 3;
repeat = len / 3;
if (remainder) {
result += tmp.substr(0, remainder);
for (int i = 0; i < repeat; i++)
result += separator + tmp.substr(remainder + i * 3, 3);
} else {
for (int i = 0; i < repeat; i++)
result += (i?separator:"") + tmp.substr(i * 3, 3);
}
if (frclen)
result += point;
num = num - (long)num;
ostringstream oss1;
oss1 << num;
tmp = oss1.str() + string(frclen + 1, '0');
result += tmp.substr(2, frclen);
return result;
}
 
F

Francesco S. Carta

It's interesting to read the whole discussion. But the material is
overwhelming. I've never heard of locale or the like. I feel happy if
I can write code in c++ instead of ANSI C. Before I begin to learn all
these, I prefer to write my own simple function (maybe I should say
method), learning locale etc must be planned for the future.
Here is my code. I use it to format currency amount, which should
contain 2 fraction digits (padded with "0").
kwwang

OK, don't worry, you'll be able to cover all the material step by step.

Reading your code it seems that I was right, you can learn something
from writing such a simple function, before diving into more advanced
subjects - I'm sure you'll take my notes in the right way, I'm starting
to dive into C myself and I feel just fine knowing that I _don't know_
and getting advices.

I'll snip all of your code, I think you know your stuff in C, you only
need to straighten out some concepts to learn the C++ way, hence I'll
post here some sparse comments.

Don't use C-style casts, and even less use them for doing simple
conversions: use "long(value)" instead of "(long)value", and chances are
that you don't even need them in this case. More about this later.

Decide the exact behaviour expected by your code: as it is now it
truncates decimals instead of rounding them upon the amount requested by
the caller.

You're hardcoding the separators and their frequency by setting just two
styles via one flag, you could make it more flexible by passing those
separators and frequency and so on as separate parameters, and with some
struggle you could give some memory to that function using static
locals, but I'd suggest you to start at once by creating a class.

A skeleton you can adapt to your task:

//-------

#include <iostream>
#include <sstream>

class NumberFormatter {
public:
NumberFormatter(int decimals = 2,
char separator = '.' )
: decimals(decimals),
separator(separator) {}

std::string operator()(double value) const;

private:
int decimals;
char separator;
};

std::string NumberFormatter::eek:perator()(double value) const {
std::stringstream result;
// intentionally silly example
result << long(value) << separator << decimals;
return result.str();
}

using namespace std;

int main() {
NumberFormatter f1;
NumberFormatter f2(3, '-');
cout << f1(4.2) << endl;
cout << f2(7.8) << endl;
return 0;
}

//-------

There are other things you can improve about your approach and I'll
eventually come back on them if others don't point them out.

Give it a shot with the above skeleton, that's an outline of what is
commonly called a function-object or functor.

Don't forget that a good book and the FAQ are two very powerful tools
for your C++ learning and for getting the best help out from this group,
start by reading sections 5 and 6 of the FAQ to ensure yourself on the
best track.

Have fun with C++, on my part I'm trying to have fun with C ;-)
 
R

red floyd

Don't use C-style casts, and even less use them for doing simple
conversions: use "long(value)" instead of "(long)value", and chances are
that you don't even need them in this case. More about this later.

And another. Don't use function/constructor style casts.

Use static_cast here. "static_cast<long>(value)"
 
F

Francesco S. Carta

And another. Don't use function/constructor style casts.

Use static_cast here. "static_cast<long>(value)"

Well, yes, I've heard that advice a lot of times, and it actually has
its use in order to quickly find all the places where an explicit
conversion is made.

I only think that sometimes that's overkill.

Consider an explicit conversion to string: I have a function that takes
a string, somewhere in the code I need to compose a message from a
string literal and a char to pass to that function:

foo(string("char ch == ") + ch);

The above looks more natural, compact and innocuous than:

foo(static_cast<string>("char ch == ") + ch);

With the further advantage that, when searching for a possibly
problematic explicit conversion, you'll avoid having to skip over the
innocuous ones.

Also consider an explicit conversion to double when doing a quick
decimal conversion, assume:

int cents = 7842;

Somebody could write:

cout << "Got " << cents * 0.01 << " euros" << endl;

I would use the functional-style conversion:

cout << "Got " << double(cents)/100 << " euros" << endl;

But this is absolutely overkill:

cout << "Got " << static_cast<double>(cents)/100 << " euros" << endl;

And, once more, will pollute the search for problematic explicit
conversions.

To resume, as I see it, it's all about coding style customs (if one has
to work in a team) and about personal needs and considerations (when one
works on a personal project).
 
W

wang

OK, don't worry, you'll be able to cover all the material step by step.

Reading your code it seems that I was right, you can learn something
from writing such a simple function, before diving into more advanced
subjects - I'm sure you'll take my notes in the right way, I'm starting
to dive into C myself and I feel just fine knowing that I _don't know_
and getting advices.

I'll snip all of your code, I think you know your stuff in C, you only
need to straighten out some concepts to learn the C++ way, hence I'll
post here some sparse comments.

Don't use C-style casts, and even less use them for doing simple
conversions: use "long(value)" instead of "(long)value", and chances are
that you don't even need them in this case. More about this later.

Decide the exact behaviour expected by your code: as it is now it
truncates decimals instead of rounding them upon the amount requested by
the caller.

You're hardcoding the separators and their frequency by setting just two
styles via one flag, you could make it more flexible by passing those
separators and frequency and so on as separate parameters, and with some
struggle you could give some memory to that function using static
locals, but I'd suggest you to start at once by creating a class.

A skeleton you can adapt to your task:

//-------

#include <iostream>
#include <sstream>

class NumberFormatter {
public:
     NumberFormatter(int decimals = 2,
                     char separator = '.' )
             : decimals(decimals),
             separator(separator) {}

     std::string operator()(double value) const;

private:
     int decimals;
     char separator;

};

std::string NumberFormatter::eek:perator()(double value) const {
     std::stringstream result;
     // intentionally silly example
     result << long(value) << separator << decimals;
     return result.str();

}

using namespace std;

int main() {
     NumberFormatter f1;
     NumberFormatter f2(3, '-');
     cout << f1(4.2) << endl;
     cout << f2(7.8) << endl;
     return 0;

}

//-------

There are other things you can improve about your approach and I'll
eventually come back on them if others don't point them out.

Give it a shot with the above skeleton, that's an outline of what is
commonly called a function-object or functor.

Don't forget that a good book and the FAQ are two very powerful tools
for your C++ learning and for getting the best help out from this group,
start by reading sections 5 and 6 of the FAQ to ensure yourself on the
best track.

Have fun with C++, on my part I'm trying to have fun with C ;-)

Thank you for your patient explaining. I'll come back to this topic
later, for I must finish the program for the company in the moment.
kwwang
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top