Exponential output with cout - should be changed....???

  • Thread starter =?ISO-8859-1?Q?Martin_J=F8rgensen?=
  • Start date
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Hi,

I have a program that reads in a couple of numbers from files and then
stores them with some latex-code but I'm not satisfied with the
exponential output, as it takes up too many character spaces. Example:

4.9e+009 - takes 8 characters space (it's a double value). It should
just become 4.9e9 (takes 5 character spaces) since all my numbers are
e-positive (no such thing as e-[something]) and all my numbers are
within 0 <= x <= 9e9. I have no idea about how to do this, but can I use
ostringstream for that?

I assume I must write the exponential number to some string or stream
and then a for loop (pseudo-code):


for( i=0; i<string.length; i++)
{
if(string == 'e')
{
/* damn... What do I do? Remove 3 characters:
the "+" and 2 zeros */
}
}

outfile << exponential_number;


But there's probably a much better and efficient method.


BTW: Something went wrong, as I tried to make a minimal example for
you... I must have overseen something:

-----------
#include <iostream>
#include <iomanip> /* for std::setfill(), std::setw() */

using namespace std;

int main()
{
double d1 = 8.126e9;

setw(5);
cout << "d1 = " << setprecision(1) << ios::scientific << d1 << endl;
return 0;
}

-----------

The above program prints:

d1 = 2568e+09

???? Where did that number come from?



As said: My real program uses outfile:

outfile << " & " << setw(15) << twoDimens[j];

So once I know how how strip 3 characters from the output (after the
'e') I can implement it... Any suggestions?


Best regards
Martin Jørgensen
 
S

Steve Pope

Martin Jørgensen said:
4.9e+009 - takes 8 characters space (it's a double value). It should
just become 4.9e9 (takes 5 character spaces) since all my numbers are
e-positive (no such thing as e-[something]) and all my numbers are
within 0 <= x <= 9e9. I have no idea about how to do this, but can I use
ostringstream for that?

I like printf() and its conversion specifications; %3.2e gives
a pretty compact output.

But not sure how to get rid of that + , other than by postfiltering.

Steve
 
B

BobR

Martin Jørgensen wrote in message
Hi,

BTW: Something went wrong, as I tried to make a minimal example for
you... I must have overseen something:

-----------
#include <iostream>
#include <iomanip> /* for std::setfill(), std::setw() */
using namespace std;

int main(){
double d1 = 8.126e9;
// > setw(5);

cout <<setw(5)<< "d1 = " << setprecision(1) << d1 << endl;
cout << "d1 = " << setprecision(1) << ios::scientific << d1 << endl;
return 0;
}

-----------
The above program prints:

d1 = 2568e+09

???? Where did that number come from?

You printed the value of "ios::scientific" in front of d1.
As said: My real program uses outfile:

outfile << " & " << setw(15) << twoDimens[j];

So once I know how how strip 3 characters from the output (after the
'e') I can implement it... Any suggestions?

Best regards
Martin Jørgensen



#include <iostream>
#include <ostream>
#include <iomanip> /* for std::setfill(), std::setw() */

int main(){
std::eek:stringstream out;
out.setf( std::ios_base::scientific );
out.precision(1);

double d1 = 8.126e9;
out << d1;
std::string Num( out.str() );
cout<<"string Num = "<< Num <<std::endl;
// out: string Num = 8.1e+009

cout <<"d1 = "<< d1 <<std::endl;
// out: d1 = 8126000000.000000

cout <<out.str()<<std::endl;
// out: 8.1e+009

size_t pos(0);
if( ( pos = Num.find("+") ) != std::string::npos){
Num.erase( pos, 3 );
}
cout<<"string Num = "<< Num <<std::endl;
// out: string Num = 8.1e9 <<------ is that what you want

return 0;
} // main()
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

BobR said:
Martin Jørgensen wrote in message
<[email protected]>...

// > setw(5);

cout <<setw(5)<< "d1 = " << setprecision(1) << d1 << endl;

Ok, thanks.
You printed the value of "ios::scientific" in front of d1.

Oh, that has a value? Hmm. I just tried it, I think you're right. It has
the value 256... That makes sense...
As said: My real program uses outfile:

outfile << " & " << setw(15) << twoDimens[j];

So once I know how how strip 3 characters from the output (after the
'e') I can implement it... Any suggestions?

Best regards
Martin Jørgensen




#include <iostream>
#include <ostream>
#include <iomanip> /* for std::setfill(), std::setw() */

int main(){
std::eek:stringstream out;
out.setf( std::ios_base::scientific );
out.precision(1);

double d1 = 8.126e9;
out << d1;
std::string Num( out.str() );
cout<<"string Num = "<< Num <<std::endl;
// out: string Num = 8.1e+009

cout <<"d1 = "<< d1 <<std::endl;
// out: d1 = 8126000000.000000

cout <<out.str()<<std::endl;
// out: 8.1e+009

size_t pos(0);
if( ( pos = Num.find("+") ) != std::string::npos){
Num.erase( pos, 3 );
}
cout<<"string Num = "<< Num <<std::endl;
// out: string Num = 8.1e9 <<------ is that what you want
Exactly!

return 0;
} // main()


If I ever came up with something that could do that, my solution would
probably be much uglier (and much more C-like)...

Btw: I changed it so it removes arbitrary number of 0's after the +. I
don't know if it's elegant (probably not) but it seem to work:


if( ( pos = Num.find("+") ) != std::string::npos) {
Num.erase( pos, 1 ); /* erase +-sign */

while( Num[pos] == '0' && pos != std::string::npos) {
Num.erase( pos, 1); /* erase all '0's */
pos++;
}
}

Thanks a lot for the hint. Now I can continue from where I was stuck :)

It was actually a bit of an exercise to implement your hint (took almost
3 hours), but I think I made it now and it's nice to see when the work
pays off :)


Best regards
Martin Jørgensen
 
B

BobR

Martin Jørgensen wrote in message ...
BobR said:
Martin Jørgensen wrote in message ...

You printed the value of "ios::scientific" in front of d1.

Oh, that has a value? Hmm. I just tried it, I think you're right. It has
the value 256... That makes sense...
#include <iostream>
#include <ostream>
#include <iomanip> /* for std::setfill(), std::setw() */

int main(){
std::eek:stringstream out;
out.setf( std::ios_base::scientific );
out.precision(1);

double d1 = 8.126e9;
out << d1;
std::string Num( out.str() );
cout<<"string Num = "<< Num <<std::endl;
// out: string Num = 8.1e+009

cout <<"d1 = "<< d1 <<std::endl;
// out: d1 = 8126000000.000000

cout <<out.str()<<std::endl;
// out: 8.1e+009

size_t pos(0);
if( ( pos = Num.find("+") ) != std::string::npos){
Num.erase( pos, 3 );
}
cout<<"string Num = "<< Num <<std::endl;
// out: string Num = 8.1e9 <<------ is that what you want
Exactly!

return 0;
} // main()

If I ever came up with something that could do that, my solution would
probably be much uglier (and much more C-like)...

Btw: I changed it so it removes arbitrary number of 0's after the +. I
don't know if it's elegant (probably not) but it seem to work:

if( ( pos = Num.find("+") ) != std::string::npos) {
Num.erase( pos, 1 ); /* erase +-sign */

while( Num[pos] == '0' && pos != std::string::npos) {
Num.erase( pos, 1); /* erase all '0's */
pos++;
}
}

Oh NOOoooo!!! std::string::npos is sometimes/usually a '-1'. That's a big
number in 'unsigned int' (assuming twos comp).

size_t Snpos( static_cast<size_t>( std::string::npos ));
std::cout<<" Snpos ="<<Snpos<<std::endl;
// output: Snpos =4294967295

What you want to compare to is the size of the string:

while( Num[pos] == '0' && pos < Num.size() ) {
Num.erase( pos, 1); /* erase all '0's */
pos++;
}

Also, I like to use the at() for index access when I'm not positive I'm in
range ( like in a dpr() loop):

try{
while( Num.at( pos ) == '0' && pos < Num.size() ) {
Num.erase( pos, 1); /* erase all '0's */
++pos;
}
} // try
catch(std::eek:ut_of_range &Oor){
std::cout<<"caught "<<Oor.what()<<std::endl;
}
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

BobR said:
Martin Jørgensen wrote in message ... -snip-
If I ever came up with something that could do that, my solution would
probably be much uglier (and much more C-like)...

Btw: I changed it so it removes arbitrary number of 0's after the +. I
don't know if it's elegant (probably not) but it seem to work:

if( ( pos = Num.find("+") ) != std::string::npos) {
Num.erase( pos, 1 ); /* erase +-sign */

while( Num[pos] == '0' && pos != std::string::npos) {
Num.erase( pos, 1); /* erase all '0's */
pos++;
}
}


Oh NOOoooo!!! std::string::npos is sometimes/usually a '-1'. That's a big
number in 'unsigned int' (assuming twos comp).

Oh, damn :)

Thanks a lot for the correction...
size_t Snpos( static_cast<size_t>( std::string::npos ));
std::cout<<" Snpos ="<<Snpos<<std::endl;
// output: Snpos =4294967295

What you want to compare to is the size of the string:

while( Num[pos] == '0' && pos < Num.size() ) {
Num.erase( pos, 1); /* erase all '0's */
pos++;
}
Ok.

Also, I like to use the at() for index access when I'm not positive I'm in
range ( like in a dpr() loop):

try{
while( Num.at( pos ) == '0' && pos < Num.size() ) {
Num.erase( pos, 1); /* erase all '0's */
++pos;

Oh, that was also stupid of me.... While I tried your Num.at()
suggestion it occured to me that it was pretty strange it didn't work....

Then I figured out that ofcourse it's a mistake to increment "pos"
because the next number is already in the right position, when the
current "0" has been deleted.... :-(

But hopefully I won't make the same mistake next time I'll have to do
something similar :)
}
} // try
catch(std::eek:ut_of_range &Oor){
std::cout<<"caught "<<Oor.what()<<std::endl;
}

Thanks again...


Best regards
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

BobR wrote:
-snip-

I just realized that there's a problem with the number: "0.000e+00"
which becomes: "0.000e" + an exception.... Here's my code:

-------
if( ( pos = exp_string.find("+") ) != std::string::npos) {
exp_string.erase( pos, 1 );

try {
while( exp_string.at( pos ) == '0' && pos < exp_string.size())
exp_string.erase( pos, 1 );
}
catch(std::eek:ut_of_range &Oor)
{
std::cout << endl << "Caught "<< Oor.what() << std::endl;
}
}
-------

But I just figured out that the try/while-line *must* say:

while( pos < exp_string.size() && exp_string.at( pos ) == '0')


Or else I get an exception... Very interesting.

But it makes completely sense because as soon as the first logical test
fails, it'll never try to figure out what the second gives.... So the
order really matters :)


Best regards
Martin Jørgensen
 
B

BobR

Martin Jørgensen wrote in message
BobR wrote:
-snip-

I just realized that there's a problem with the number: "0.000e+00"
which becomes: "0.000e" + an exception.... Here's my code:

-------
if( ( pos = exp_string.find("+") ) != std::string::npos) {
exp_string.erase( pos, 1 );
try {
while( exp_string.at( pos ) == '0' && pos < exp_string.size())
exp_string.erase( pos, 1 );
}
catch(std::eek:ut_of_range &Oor){
std::cout << endl << "Caught "<< Oor.what() << std::endl;
}
}
-------
But I just figured out that the try/while-line *must* say:

while( pos < exp_string.size() && exp_string.at( pos ) == '0')

Or else I get an exception... Very interesting.

But it makes completely sense because as soon as the first logical test
fails, it'll never try to figure out what the second gives.... So the
order really matters :)

An if() in the while loop after the *.erase() would have prevented the
exception:

if( pos >= exp_string.size() ){ break; }

I almost didn't mention the *.at(). I guess that '++pos' was tugging at the
back of my mind. Pretty neat how that try/catch works, eh. I'm sure you would
have spent a long time looking for the bug without it.


Yeah, in my prior post I was in a big hurry[1]. I wanted to stop you before
you 'copy/paste'd that 'string::npos' code in 531 places, and then would have
to go back and correct it all. <G>

Hopefully you only use it one place, or have put it in a little helper
function.

You also stated that the doubles were all positive, so, I didn't code for '-'
or '0.0'.
[ I generally don't think of zero haveing a sign, but, 'stream' has a
different attitude. :-} ]

[1] - so I spotted errors after I posted. Grrrr!! <G>
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

BobR said:
Martin Jørgensen wrote in message



An if() in the while loop after the *.erase() would have prevented the
exception:

if( pos >= exp_string.size() ){ break; }

Agreed. I like the short formulation better:

while( pos < exp_string.size() && exp_string.at( pos ) == '0')

Because I then have 1 less line and still get the same effect (I
think)... I also hate those "break"'s inside loops, but I agree that
sometimes I can't avoid them so easily and when such a situation occurs
I've sometimes inserted a couple of breaks...

But it makes the code so ugly, I think :)

In my bs.c. project which I handed in this summer (written in C) I also
used "goto" because I had a couple of for-loops and break wasn't enough
if I wanted to quit the inner-most for-loop and exit a couple of
for-loops completely... It was really really "ugly" :)
I almost didn't mention the *.at(). I guess that '++pos' was tugging at the
back of my mind. Pretty neat how that try/catch works, eh. I'm sure you would
have spent a long time looking for the bug without it.

Yep! :)
Yeah, in my prior post I was in a big hurry[1]. I wanted to stop you before
you 'copy/paste'd that 'string::npos' code in 531 places, and then would have
to go back and correct it all. <G>

Hopefully you only use it one place, or have put it in a little helper
function.

Yep, it's inside a function so I only use it 1 place...
You also stated that the doubles were all positive, so, I didn't code for '-'
or '0.0'.
Exactly.

[ I generally don't think of zero haveing a sign, but, 'stream' has a
different attitude. :-} ]

[1] - so I spotted errors after I posted. Grrrr!! <G>

IMHO the important thing is that I was stuck and got a bit of help to
continue on my own, so thanks a lot for that :)


Best regards
Martin Jørgensen
 

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

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top