how to display 12345 as 12,345 ??

N

news.hku.hk

suppose i have:

int price1 = 35000;
int price2 = 600;
int price3 = 8765;
int price4 = 120000;
int price5 = 3800000;

and i want to output to screen the following:

35,000
600
8,765
120,000
3,800,000

what should i do ?? any good function to do this ??
 
M

Marcin Kalicinski

U¿ytkownik "news.hku.hk said:
suppose i have:

int price1 = 35000;
int price2 = 600;
int price3 = 8765;
int price4 = 120000;
int price5 = 3800000;

and i want to output to screen the following:

35,000
600
8,765
120,000
3,800,000

what should i do ?? any good function to do this ??

Not in the standard. You'll have to do it yourself. I believe it is quite
simple.

regards,
Marcin
 
J

John Ericson

news.hku.hk said:
suppose i have:

int price1 = 35000;
int price2 = 600;
int price3 = 8765;
int price4 = 120000;
int price5 = 3800000;

and i want to output to screen the following:

35,000
600
8,765
120,000
3,800,000

what should i do ?? any good function to do this ??

You could look up facets, and check out Dinkumware.
 
J

JKop

I've done this before. I've adapted it for the purpose of this post, but
here goes (Check for bugs before you use it!):


char szBuffer[30]; //Global Variable

char* GenerateString(unsigned long);

int main(void)
{
cout << GenerateString(12345);
}


char* GenerateString(unsigned long Numbr)
{
szBuffer[29] = '\0';

char* pChar = &m_szBuffer[28];

unsigned long char_counter = 0;
unsigned long comma_counter = 0;
unsigned long nResult; //will be initialized
unsigned long nTempValue = Numbr;

for(;;)
{
nResult = 0;

//I used to use the method below, but it's FAR too slow
/*
while ( nTempValue >= 10 )
{
nTempValue -= 10;
nResult += 1;
}*/

nResult = nTempValue / 10;
nTempValue %= 10;

*pChar = ( ( '0' ) + ( nTempValue ) );
pChar -= 1;


char_counter +=1;

nTempValue = nResult; //Very Important!

if (!nTempValue) break; //This line prevents ",345" being
generated

char_counter += 1;


if ( comma_counter == 3 )
{
*pChar = ',';
pChar -= 1;
char_counter += 1;
comma_counter = 0;
}
} //End of "For"

return pChar;

}


Hope that helps. Also, you may try incorporating it into a class ( I did! )
and also overide the ostream "<<" operator! That'd be dead handy. I'd post
the class I wrote for it but it had a very specific purpose other than just
genrating these strings.


-JKop
 
P

pembed2003

news.hku.hk said:
suppose i have:

int price1 = 35000;
int price2 = 600;
int price3 = 8765;
int price4 = 120000;
int price5 = 3800000;

and i want to output to screen the following:

35,000
600
8,765
120,000
3,800,000

what should i do ?? any good function to do this ??

Hi,
I am new to C++ too so my solution might not be very good. Anyway, I
will try something like:

void _display_number(int v, int n){
if(v >= 1000){
int r = v % 1000;
_display_number(v / 1000,n);
printf(",%03d",r); // how to translate that into
std::cout<<...?
}else{
printf("%s%d\n",n ? "-":"",v);
}
}

void display_number(int v){
_display_number(v < 0 ? -v : v,v < 0);
}

int main(int argc,char** argv){
display_number(35000);
display_number(600);
display_number(8765);
display_number(120000);
display_number(3800000);
display_number(-3800000);
}

The program prints something like:

35,000
600
8,765
120,000
3,800,000
-3,800,000

HTH. I am here to learn as well so if anyone can help me improve the
program, I am happy to see it. Thanks!
 
J

John Ericson

JKop said:
I've done this before. I've adapted it for the purpose of this post, but
here goes (Check for bugs before you use it!):


char szBuffer[30]; //Global Variable

char* GenerateString(unsigned long);

int main(void)
{
cout << GenerateString(12345);
}


char* GenerateString(unsigned long Numbr)
{
szBuffer[29] = '\0';

char* pChar = &m_szBuffer[28];

unsigned long char_counter = 0;
unsigned long comma_counter = 0;
unsigned long nResult; //will be initialized
unsigned long nTempValue = Numbr;

for(;;)
{
nResult = 0;

//I used to use the method below, but it's FAR too slow
/*
while ( nTempValue >= 10 )
{
nTempValue -= 10;
nResult += 1;
}*/

nResult = nTempValue / 10;
nTempValue %= 10;

*pChar = ( ( '0' ) + ( nTempValue ) );
pChar -= 1;


char_counter +=1;

nTempValue = nResult; //Very Important!

if (!nTempValue) break; //This line prevents ",345" being
generated

char_counter += 1;


if ( comma_counter == 3 )
{
*pChar = ',';
pChar -= 1;
char_counter += 1;
comma_counter = 0;
}
} //End of "For"

return pChar;

}


Hope that helps. Also, you may try incorporating it into a class ( I did! )
and also overide the ostream "<<" operator! That'd be dead handy. I'd post
the class I wrote for it but it had a very specific purpose other than just
genrating these strings.


-JKop

How about (untested code, and YMMV)

#include <iostream>
#include <locale>

int main()
{
using namespace std;
cout.imbue(locale("English"));
cout << 12345 << '\n';
}

;) JE
 
N

news.hku.hk

thanks for all of your's help
but i still can't grasp the idea of the algorithm
maybe could anyone explain in words(preferably with c++ codes) that how the
algorithm works ??
Thanks
 
R

rossum

suppose i have:

int price1 = 35000;
int price2 = 600;
int price3 = 8765;
int price4 = 120000;
int price5 = 3800000;

and i want to output to screen the following:

35,000
600
8,765
120,000
3,800,000

what should i do ?? any good function to do this ??
Yet another alternative. This one converts the number into a string
and puts the commas into the string. Not necessarily better, just
different.

rossum


#include <string>
#include <sstream>
#include <iostream>
#include <cstdlib>

std::string comma(int num) {
// Deal with negatives
if(num < 0) { return "-" + comma(std::abs(num)); }

// Convert number to string
std::stringstream ss;
ss << num;
std::string num_string = ss.str();

// Insert a comma every third position
for (int i = num_string.length() - 3; i > 0; i -= 3) {
num_string.insert(i, 1, ',');
} // end for

return num_string;
} // end comma()

//---------------------------

int main() {
std::cout << comma(-3800000) << '\n'
<< comma(-120000) << '\n'
<< comma(-35000) << '\n'
<< comma(-8765) << '\n'
<< comma(-600) << '\n'
<< comma(-50) << '\n'
<< comma(-4) << '\n'
<< comma(0) << '\n'
<< comma(4) << '\n'
<< comma(50) << '\n'
<< comma(600) << '\n'
<< comma(8765) << '\n'
<< comma(35000) << '\n'
<< comma(120000) << '\n'
<< comma(3800000) << std::endl;
return EXIT_SUCCESS;
} // end main()
 
S

Siemel Naran

This is a good solution. Not sure why everyone is re-inventing the wheel.
using namespace std;
cout.imbue(locale("English"));
cout << 12345 << '\n';

But, is there a locale named "English"?
 
N

news.hku.hk

Thanks, i see your point
but how to return to the original state??
because i just want to insert the comma in someline while later i just want
to display ordinary numbers.

also, from your quotation, if i add one more cout line after cout << 12345
<<'\n';

i.e. cout << 543532 << '\n';
there will be runtime error.......what's up ??
 
S

Siemel Naran

news.hku.hk said:
Thanks, i see your point
but how to return to the original state??
because i just want to insert the comma in someline while later i just want
to display ordinary numbers.

Haven't tried it yet, but approaches I suggest is: (1) use 2 locales, and
imbue cout with first locale when you want num_put to put comma symbols and
default locale when you don't want comma symbols, (2) create a new type
Amount for which operator<<(ostream&, Amount) uses num_put for Amount
objects and this num_put uses comma symbols. See my response in the thread
with subject "convert hex to oct" for this imbue, use_facet, etc. But there
was a C++ magazine that had and maybe still has lots of articles on these
ideas, and I think the articles were by Plauger, so maybe you can browse for
that too.
also, from your quotation, if i add one more cout line after cout << 12345
<<'\n';

i.e. cout << 543532 << '\n';
there will be runtime error.......what's up ??

No error. I don't know what quotation you're talking about.
 
J

Joe Hotchkiss

news.hku.hk said:
Thanks, i see your point
but how to return to the original state??
because i just want to insert the comma in someline while later i
just want to display ordinary numbers.
cout.imbue(locale("C"));

Since the sample works fine for me, I would assume there is. At least for my
compiler.
Why not try it and see with your compiler?

--
Regards,

Joe Hotchkiss,
http://joe.hotchkiss.com

XXXXXXXXXXXXXXXXXXXXXXXXX
X joe.hotchkiss X
X at baesystems.com X
XXXXXXXXXXXXXXXXXXXXXXXXX
 
J

Jerry Coffin

news.hku.hk said:
suppose i have:

int price1 = 35000;
int price2 = 600;
int price3 = 8765;
int price4 = 120000;
int price5 = 3800000;

and i want to output to screen the following:

35,000
600
8,765
120,000
3,800,000

what should i do ?? any good function to do this ??

You might want to look at commafmt.c at www.snippets.org.
 
E

E. Robert Tisdale

news.hku.hk said:
Suppose that I have:

int price1 = 35000;
int price2 = 600;
int price3 = 8765;
int price4 = 120000;
int price5 = 3800000;

and that I want to output to screen the following:

35,000
600
8,765
120,000
3,800,000

What should I do? Are there any good functions to do this?

cat main.cc
#include <iostream>
#include <iomanip>

class Price {
private:
// representation
int I;
public:
// functions
friend
std::eek:stream& operator<<(std::eek:stream& os, const Price& i);
// operators
// implicit
operator int(void) const { return I;}
operator int(void) { return I;}
// constructors
Price(int i = 0): I(i) { }
};

inline
std::eek:stream& operator<<(std::eek:stream& os, const Price& i) {
int q = (int)i/1000;
int r = (int)i%1000;
if (0 < q)
os << Price(q) << ','
<< std::setfill('0') << std::setw(3) << r;
else
os << r;
return os;
}

int main(int argc, char* argv[]) {
const
int price[] = {35000, 600, 8765, 120000, 3800000};
const
size_t n = sizeof(price)/sizeof(price[0]);
for (size_t j = 0; j < n; ++j)
std::cout << Price(price[j]) << std::endl;
return 0;
}
g++ -Wall -ansi -pedantic -o main main.cc
./main
35,000
600
8,765
120,000
3,800,000
 
R

rossum

On 26 Apr 2004 12:30:35 -0700, (e-mail address removed) (pembed2003)
wrote:

[snip OP]
Hi,
I am new to C++ too so my solution might not be very good. Anyway, I
will try something like:
Show what headers you are including. Code should be compilable as is,
just cut and paste.
void _display_number(int v, int n){
Avoid leading underscores, they are used internally by compilers so if
you pick the wrong name you will get a compilation error. Since
compilers differ this might also make your code non-portable.
Trailing underscores are safer and hence better. So change
_display_number() to display_number_().

You have a good self explanatory name for the function, but you use
short cryptic names for the two parameters. Better to change v to
value and n to is_negative so they are more self explanatory.

The second parameter is a yes/no flag so it is better to declare is as
a bool which gives a better indication of its purpose. It is possible
to eliminate this parameter by taking a slightly different approach to
the recursion.
if(v >= 1000){
Put a space between the if and the open bracket: if (value >= 1000) {.
This is to differentiate it from function calls. ^--added space
int r = v % 1000;
Another short cryptic variable name. Change it to something
meaningful.
_display_number(v / 1000,n);
Better to put a space after the comma which separates the parameters.
printf(",%03d",r); // how to translate that into
std::cout<<...?
Better to put a space after the second comma which separates the
parameters.

For cout look up the I/O manipulators.
}else{
printf("%s%d\n",n ? "-":"",v);
The ternary operator ?: can make for unreadable code. Better to use
it sparingly. If you do use it then put spaces round both the '?' and
the ':' for clarity. Again spaces after any commas that separate
parameters are easier to read.

Are you really sure about that '\n' there? I hope that you
cut-and-pasted this rather than typed it from scratch.
}
}

void display_number(int v){
_display_number(v < 0 ? -v : v,v < 0);
Where the ternary operator has a boolean expression it is better to
put the expression in brackets: (v < 0) ? -v : v to improve
readability. Again put a space after the parameter separating comma.
}

int main(int argc,char** argv){
display_number(35000);
display_number(600);
display_number(8765);
display_number(120000);
display_number(3800000);
display_number(-3800000);

Main does not require a return value, but it is better style to
include it explicitly. I tend to use the EXIT_SUCCESS and
EXIT_FAILURE macros.
}

The program prints something like:

35,000
600
8,765
120,000
3,800,000
-3,800,000

HTH. I am here to learn as well so if anyone can help me improve the
program, I am happy to see it. Thanks!

Hope you find that useful.

rossum
 
J

John Ericson

Siemel Naran said:
This is a good solution. Not sure why everyone is re-inventing the wheel.


But, is there a locale named "English"?

;) No guarantees there - on my system there is (Win XP,
VC++ 2003). I've got a few books to go before hitting Langer
and Kreft's "Standard C++ IOStreams and Locales," but I'm
looking forward to what looks like it's going to be a good
read.
- -
Best regards, JE
 
S

Siemel Naran

Joe Hotchkiss said:
Since the sample works fine for me, I would assume there is. At least for my
compiler.
Why not try it and see with your compiler?

Fair enough, but the standard does not appear to mention this.
 
P

pembed2003

rossum said:
On 26 Apr 2004 12:30:35 -0700, (e-mail address removed) (pembed2003)
wrote:

[snip OP]
Hi,
I am new to C++ too so my solution might not be very good. Anyway, I
will try something like:
Show what headers you are including. Code should be compilable as is,
just cut and paste.

Is this a rule for this newsgroup to always include only complete
program as an answer and must be compilable by cut and paste? Just
curious, new to this newsgroup...
Avoid leading underscores, they are used internally by compilers so if
you pick the wrong name you will get a compilation error. Since
compilers differ this might also make your code non-portable.
Trailing underscores are safer and hence better. So change
_display_number() to display_number_().

Great. I always forget that.
You have a good self explanatory name for the function, but you use
short cryptic names for the two parameters. Better to change v to
value and n to is_negative so they are more self explanatory.

Great. Good advice. Will most likely do but maybe not neccessary in
this case where the parameters are already pretty clear (?)

I don't feel like:

display_number_(int number_to_display_with_comma, bool is_negative)

especially:

display_number_(int v, int n)

where the function name itself already communicate back to the user
that the function is make to display a number. Maybe the second
parameter isn't so clear as what it does...
The second parameter is a yes/no flag so it is better to declare is as
a bool which gives a better indication of its purpose. It is possible
to eliminate this parameter by taking a slightly different approach to
the recursion.

Yes. Totally agree. Can you show me how?
Put a space between the if and the open bracket: if (value >= 1000) {.
This is to differentiate it from function calls. ^--added space

Sorry. This one I might have to disagree. I think it's a personal
thing and I never found:

if(v >= 1000){

to be less readable than:

if (v >= 1000) {

Since in this case, the compiler doesn't care. I will stick with my
way.
Another short cryptic variable name. Change it to something
meaningful.

More meaningful variable name is usually a good idea but just looking
at the right side of assignment, one can pretty much firgure out what
r is, right?

I mean, do you seriously think:

int remainder = v % 1000;

will communicate so much better than:

int r = v % 1000;

All the action is on the right hand side AND it is so short.
Better to put a space after the comma which separates the parameters.

Agree.

Better to put a space after the second comma which separates the
parameters.

Agree.


For cout look up the I/O manipulators.

Sure.

The ternary operator ?: can make for unreadable code. Better to use
it sparingly.

I think I use it only twice in my code above. Does it count as
sparingly?
If you do use it then put spaces round both the '?' and
the ':' for clarity. Again spaces after any commas that separate
parameters are easier to read.

Make sense.
Are you really sure about that '\n' there? I hope that you
cut-and-pasted this rather than typed it from scratch.

No, it's a bug. I should have state that so OP won't make the same
mistake.
Where the ternary operator has a boolean expression it is better to
put the expression in brackets: (v < 0) ? -v : v to improve
readability. Again put a space after the parameter separating comma.

I never try that but looking at your code, I think it does improve
readability so I will remember to do that next time.
Main does not require a return value, but it is better style to
include it explicitly. I tend to use the EXIT_SUCCESS and
EXIT_FAILURE macros.

Agree.


Hope you find that useful.

Very useful.

I respect your comments because it will make me a better programmer.
Thanks!
 
J

John Harrison

Is this a rule for this newsgroup to always include only complete
program as an answer and must be compilable by cut and paste? Just
curious, new to this newsgroup...

Its not a rule, but its obviously a good idea if you want to get help.

If you submit partial code, then there is a good chance that people won't be
able to answer the question because you missed out some vital piece of
information. Its amazing how many posters, despite not understand why their
code doesn't work are convinced that they know where the mistake is in their
code. Eventually when you get them to post more code, you often find that
the real error was in some part of the code they didn't originally post.

If you type in code rather than cut and paste, you are liable to get your
typing mistakes corrected instead of your real question answered. Given that
many newbies post to this group, its often hard to tell the difference
between a typing mistake and a genuine misunderstanding.

john
 
D

Dietmar Kuehl

Just a few notes from the view of someone who has implemented this stuff...

news.hku.hk said:
but how to return to the original state??

If you only need an occasional switch between locales, you can just switch
them by calling 'imbue()', eg.:

std::locale english("English");
std::cout.imbue(english);
// ...
std::cout.imbue(std::locale());

The default constructor just uses a copy of the global locale (internally,
locales are a reference counted collection of facets and copying them is
fast). However, the 'imbue()' operation itself is relatively expensive.
In particular, it is reasonable for streams to cache quite a few values
obtained from a locale to improve the overall performance. As a result,
you might consider to use a separate stream writing to the same destination
but with a different locale, eg.:

std::eek:stream ecout(std::cout.rdbuf());
ecout.imbue(std::locale("English"));
ecout << "english: " << 10000 << "\n";
std::cout << "normal: " << 10000 << "\n";

Since creation of streams themselves is also relatively expensive, you
might want to keep the additional stream around rather than creating it
each time around (which would probably be more expensive than switching
locales).

Also, the names for the named locales are not specified by the standard.
Of course, you can figure out which locales are around when porting your
application to another compiler/library but for portable code you would
probably create an own locale with a specialized 'std::numpunct<char>'
facet. Here is a brief code example (entirely untested, however...):

#include <locale>
class mynumpunct:
public std::numpunct<char> {
std::string do_grouping() const {
char group[] = { 3, 0 };
return group;
}
};
int main() {
std::locale myloc(std::locale(), new mynumpunct);
std::cout.imbue(myloc);
// ...
}

Actually, you can do funny things with the grouping: it does not have to
be the same amount of characters every time! For example, if 'group'
would be initialized like

char group[] = { 1, 2, 3, 0 };

you would get "1,234,56,7" when printing "1234567" (as an integer, that is;
grouping is not applied to strings, of course).
also, from your quotation, if i add one more cout line after cout << 12345
<<'\n';

i.e. cout << 543532 << '\n';
there will be runtime error.......what's up ??

This seems to be an error somewhere in the code you use: there should be
no problem using 'std::cout' even with a modified locale.
 

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,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top