Formatting floating point values in ostream objects

T

tron.thomas

This C program:

#include <stdio.h>
#include <math.h>

int main()
{
float value;
for(value = -1.0f; 1.1f > value; value += 0.1f){
printf("%.1f\n", value);
}

return 0;
}

Produces this output:

-1.0
-0.9
-0.8
-0.7
-0.6
-0.5
-0.4
-0.3
-0.2
-0.1
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0

Trying to write an equivalent C++ program using ostream has proven
tricky. Here is a solution I came up with:

#include <iostream>
#include <cmath>

int main()
{
static const float TOLERANCE = 0.0001f;

using std::cout;
cout << std::showpoint;

for(float value = -1.0f; 1.1f > value; value += 0.1f){
cout.precision(1);

float integral = ::floor(value);
if(TOLERANCE > ::fabsf(value - integral)){
value = integral;
cout.precision(2);
}

cout << value << '\n';
}

return 0;
}

It seems like a lot more work to accomplish the same thing. I wonder
if there is a better approach
What is the best way to produce this kind of output using an ostream
object?
 
A

Alf P. Steinbach

* (e-mail address removed):
This C program:

#include <stdio.h>
#include <math.h>

int main()
{
float value;
for(value = -1.0f; 1.1f > value; value += 0.1f){
printf("%.1f\n", value);
}

return 0;
}

Produces this output:

-1.0
-0.9
-0.8
-0.7
-0.6
-0.5
-0.4
-0.3
-0.2
-0.1
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0

Not necessarily, because you have no guarantee that the next value will
be >= 1.1. You're dealing with floating point arithmetic. So, instead
of updating the floating point value, compute it, and instead of type
float, use type double (use type float only when there's good reason).

Expressed in C++:

#include <cstdio>

int main()
{
for( int i = -10; i <= +10; ++i )
{
std::printf( "%.1f\n", i/10.0 );
}
}

Trying to write an equivalent C++ program using ostream has proven
tricky. Here is a solution I came up with:

#include <iostream>
#include <cmath>

int main()
{
static const float TOLERANCE = 0.0001f;

Don't use all uppercase identifiers except for macros.


using std::cout;
cout << std::showpoint;

I hate iostreams so I had to look up "showpoint".

for(float value = -1.0f; 1.1f > value; value += 0.1f){
cout.precision(1);

float integral = ::floor(value);
if(TOLERANCE > ::fabsf(value - integral)){
value = integral;
cout.precision(2);
}

This does a bit more, or a different thing, than the C program.


cout << value << '\n';
}

return 0;
}

It seems like a lot more work to accomplish the same thing.

Well, it's not the same thing: you let the C++ program do more.

I wonder
if there is a better approach
What is the best way to produce this kind of output using an ostream
object?

No "best" way (unless you list your criteria), however, much simpler:

#include <iostream>
#include <iomanip>

int main()
{
using namespace std;
for( int i = -10; i <= +10; ++i )
{
cout << fixed << setprecision( 1 ) << i/10.0 << endl;
}
}

Cheers, & hth.,

- Alf
 
J

James Kanze

This C program:
#include <stdio.h>
#include <math.h>
int main()
{
float value;
for(value = -1.0f; 1.1f > value; value += 0.1f){
printf("%.1f\n", value);
}
return 0;
}
Produces this output:

Trying to write an equivalent C++ program using ostream has proven
tricky.

What's wrong with:

#include <iostream>

int
main()
{
std::cout.precision( 1 ) ;
std::cout.setf( std::ios::fixed, std::ios::floatfield ) ;
for ( float value = -1.0f ; 1.1f > value ; value += 0.1f ) {
std::cout << value << '\n' ;
}
std::cout.flush() ;
return 0 ;
}

? It should have exactly the same semantics as your C program.

(Of course, in a real application, you'd doubtlessly be using a
user defined manipulator, depending on the semantics of the
float. Logical mark-up, not physical.)
 
J

Juha Nieminen

Alf said:
Don't use all uppercase identifiers except for macros.

Isn't that a question of style?

And IMO, if it's a constant then using all uppercase is sensible. It
doesn't matter if it's a preprocessor constant or a const variable.
 
A

Alf P. Steinbach

* Juha Nieminen:
Isn't that a question of style?

Mostly it's a question of language (e.g. Java has no preprocessor), but
to some degree yes also of style, or lack thereof <g>.

For the rationale of reserving all uppercase for macros, see e.g. the
language creator's FAQ at <url:
http://www.research.att.com/~bs/bs_faq2.html#macro>.

And IMO, if it's a constant then using all uppercase is sensible.

Nope. You risk name collision with macros. Also you're incorrectly
indicating that it's a macro, and you're embedding type information in
the name so that (same problem as with Hungarian evilness) a change of
the constness then requires a change of name, or leaves the name
indicating something that's now false.

It
doesn't matter if it's a preprocessor constant or a const variable.

Yes, it does, very very much. ;-)

They're fundamentally different in the way the respect C++ scope rules.


Cheers, & hth.,

- Alf
 
J

Juha Nieminen

Alf said:
Also you're incorrectly
indicating that it's a macro, and you're embedding type information in
the name so that (same problem as with Hungarian evilness) a change of
the constness then requires a change of name, or leaves the name
indicating something that's now false.

And if you use your suggested scheme, if you ever change a #define
into a const variable, you'll have to change the name.
 
B

Bo Persson

Juha said:
And if you use your suggested scheme, if you ever change a #define
into a const variable, you'll have to change the name.

Yes, so don't use #defines! :)


Bo Persson
 
J

James Kanze

And if you use your suggested scheme, if you ever change a #define
into a const variable, you'll have to change the name.

Certainly. You've significantly changed the semantics, so you
have to look at all uses of it again, to be sure that they are
still OK. Changing the name ensures that you do. (Generally
speaking, of course, if it is a constant, it should never be a
macro to begin with. Macros should be reserved for things that
can't be done otherwise.)

That's also an argument against using all caps for const: one
man's constant is another man's variable, and in practice,
constants do have a tendency of becoming variables, e.g. read
from a configuration file. Long before it became a widely
recognized and generally accepted rule, I'd dropped all caps
from constants because of this---I also don't use all caps for
constants in Java, for the same reason.
 
J

Juha Nieminen

Bo said:
Yes, so don't use #defines! :)

But in that case all uppercase names become free to use, so you could
as well use them for names of constants... ;)
 
T

tron.thomas

What's wrong with:

    #include <iostream>

    int
    main()
    {
        std::cout.precision( 1 ) ;
        std::cout.setf( std::ios::fixed, std::ios::floatfield ) ;
        for ( float value = -1.0f ; 1.1f > value ; value += 0.1f ) {
            std::cout << value << '\n' ;
        }
        std::cout.flush() ;
        return 0 ;
    }

?  It should have exactly the same semantics as your C program.

(Of course, in a real application, you'd doubtlessly be using a
user defined manipulator, depending on the semantics of the
float.  Logical mark-up, not physical.)

--
James Kanze (GABI Software)             email:[email protected]
Conseils en informatique orientée objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Thanks James. That is exactly what I was looking for. I think as long
as I define my precision correctly this code with the result I want
for the actual problem I'm trying to solve.
 
E

Erik Wikström

But in that case all uppercase names become free to use, so you could
as well use them for names of constants... ;)

But someone who do not know that you do not use defines might think that
they are defines. There are a lot of things that could be better, but
due to historical reasons we have to live with. All uppercase names are
for historical reasons reserved for defines. You can of course do as you
want but you should be aware of the "dangers".
 
A

Alf P. Steinbach

* (e-mail address removed):
Thanks James. That is exactly what I was looking for. I think as long
as I define my precision correctly this code with the result I want
for the actual problem I'm trying to solve.

Note that James very very carefully wrote "same semantics".

That does not mean that the code above has a well-defined result.

Your code, and the above equivalence, doesn't have a well-defined
result, as discussed in the first reply in the thread.


Cheers, & utterly perplexed, as so often is the case,

- Alf
 
J

James Kanze

* (e-mail address removed):
Note that James very very carefully wrote "same semantics".
That does not mean that the code above has a well-defined result.

Quite. I only addressed the formatting issue, not the more
general problem of floating point arithmetic. This sort of loop
in floating point is just asking for trouble.
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
474,039
Messages
2,570,376
Members
47,026
Latest member
TishaMadri

Latest Threads

Top