C++ Primer 4/e exercise 1.19

A

arnuld

STATEMENT: Write a program that prompts the user for two numbers and
writes each number in the range specified by the two numbers to the
standard output. Revise the program so that it never prints more than
10 numbers per line.

i have written the 1st part of it which prints the range:

#include <iostream>

int main()
{
std::cout << "Enter 2 numbers: ";
int v1, v2;
std::cin >> v1 >> v2;

int lower,upper;
if(v1 <= v2)
{
lower = v1;
upper = v2;
}
else
{
lower = v2;
upper = v1;
}

for(int i=lower; i <= upper; ++i)
std::cout << i
<<" "; // space between two numbers


std:: cout << "\nThank you ;-)" << std::endl;
}


it works but i am not able to print 10 numbers per line. i tried to
embed a for loop within the original for loop i used in the programme
but that does not work.

any hints ?
 
A

AG

for(int i=lower; i <= upper; ++i)
std::cout << i
<<" "; // space between two numbers


std:: cout << "\nThank you ;-)" << std::endl;

int number_counter=0;
for(int i=lower;i<=upper;++i)
{
std::cout << i << " ";
number_counter++;
if(number_counter>9)
{
std::cout << "\n";
}
}

warning : this code still does not meet the requirements (on purpose).
I let you do it.
AG.
 
A

arnuld

int number_counter=0;
for(int i=lower;i<=upper;++i)
{
std::cout << i << " ";
number_counter++;
if(number_counter>9)
{
std::cout << "\n";
}

}

warning : this code still does not meet the requirements (on purpose).
I let you do it.
AG.

yes, it works:

int counter = 0;
for(int i=lower; i <= upper; ++i)
{
if(counter > 9)
{
std::cout << std::endl;
counter =0;
}
std::cout << i << ' '; // inserts space between 2 numbers
++counter;
}


this is the output:
[arnuld@arch cpp]$ g++ -ansi -pedantic -Wall -Wextra ex-1.19.cpp
[arnuld@arch cpp]$ ./a.out
Enter 2 numbers: 2 10
2 3 4 5 6 7 8 9 10
Thank you Bantu ;-)
[arnuld@arch cpp]$ 2 111
-bash: 2: command not found
[arnuld@arch cpp]$ ./a.out
Enter 2 numbers: 2 80
2 3 4 5 6 7 8 9 10 11
12 13 14 15 16 17 18 19 20 21
22 23 24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39 40 41
42 43 44 45 46 47 48 49 50 51
52 53 54 55 56 57 58 59 60 61
62 63 64 65 66 67 68 69 70 71
72 73 74 75 76 77 78 79 80
Thank you ;-)
[arnuld@arch cpp]$


BTW, how can i make the output equally dispersed ? in C i can use "%.
2d". what in C++ ?
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

yes, it works:

int counter = 0;
for(int i=lower; i <= upper; ++i)
{
if(counter > 9)
{
std::cout << std::endl;
counter =0;
}
std::cout << i << ' '; // inserts space between 2 numbers
++counter;
}

Take some time to get familiar with the % operator for integers, it can
be used to simplify the code slightly.
this is the output:
[arnuld@arch cpp]$ g++ -ansi -pedantic -Wall -Wextra ex-1.19.cpp
[arnuld@arch cpp]$ ./a.out
Enter 2 numbers: 2 10
2 3 4 5 6 7 8 9 10
Thank you Bantu ;-)
[arnuld@arch cpp]$ 2 111
-bash: 2: command not found
[arnuld@arch cpp]$ ./a.out
Enter 2 numbers: 2 80
2 3 4 5 6 7 8 9 10 11
12 13 14 15 16 17 18 19 20 21
22 23 24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39 40 41
42 43 44 45 46 47 48 49 50 51
52 53 54 55 56 57 58 59 60 61
62 63 64 65 66 67 68 69 70 71
72 73 74 75 76 77 78 79 80
Thank you ;-)
[arnuld@arch cpp]$


BTW, how can i make the output equally dispersed ? in C i can use "%.
2d". what in C++ ?

Take a look at ostream.width(), and ostream.fill(), beware though, the
settings reset after each output. People can say what they want but
printf() beats the shit out of C++ streams when it comes to formated
output of simple data types.
 
J

James Kanze

STATEMENT: Write a program that prompts the user for two numbers and
writes each number in the range specified by the two numbers to the
standard output. Revise the program so that it never prints more than
10 numbers per line.
i have written the 1st part of it which prints the range:
#include <iostream>
int main()
{
std::cout << "Enter 2 numbers: ";
int v1, v2;
std::cin >> v1 >> v2;

int lower,upper;
if(v1 <= v2)
{
lower = v1;
upper = v2;
}
else
{
lower = v2;
upper = v1;
}

Just a nit, but I'd replace the above with something like:

int upper ;
int lower ;
std::cin >> lower >> upper ;
// Check for errors here!!!
if ( upper < lower ) {
std::swap( upper, lower ) ;
}

No need for the extra variables.
for(int i=lower; i <= upper; ++i)
std::cout << i
<<" "; // space between two numbers
std:: cout << "\nThank you ;-)" << std::endl;
}
it works but i am not able to print 10 numbers per line. i tried to
embed a for loop within the original for loop i used in the programme
but that does not work.

It's possible to use a nested loop, with the outer loop
outputting each line, and the inner loop the elements.
Something like:

for ( int i = lower ; i <= upper ; i += 10 ) {
for ( int j = i ; j < i + 10 && j <= upper ; ++ j ) {
...
}
std::cout << '\n' ;
}

(Note the condition on the inner loop.)

That actually works well for this simple example, but generally,
I like to manage the line length separately, using a variable
just for it:

int inLineCount = 0 ;
for ( ... ) {
if ( inLineCount == 0 ) {
// Output start of line, etc.
} else {
// Output separator between values.
}
// Output value
++ inLineCount ;
if ( inLineCount >= N ) {
// Output end of line data, etc., and new line.
inLineCount = 0 ;
}
}
if ( inLineCount != 0 ) {
// Output end of line data, etc., and new line.
// In some cases, you might want to treat an
// incomplete last line differently.
}

It's a little bit more complicated, but is the most adaptable.
It's become a pattern in my code.
 
J

James Kanze

On 2007-07-12 10:01, arnuld wrote: [...]
BTW, how can i make the output equally dispersed ? in C i can use "%.
2d". what in C++ ?
Take a look at ostream.width(), and ostream.fill(), beware though, the
settings reset after each output. People can say what they want but
printf() beats the shit out of C++ streams when it comes to formated
output of simple data types.

People can say what they will, but C++ streams are far easier
and more intuitive for just about any formatting. (Actually,
neither is very intuitive, and the one you know best is
generally the simpler. iostream is probably simpler to learn,
however, in addition to being the safest and the most
extendable.) In this case:

std::cout << std::setw( 2 ) << n ;

does the job. Except, of course, that he doesn't want 2,
because the user might have input 1001, 1020. He needs

width = ciel( log10( upper ) ) ;
// ...
std::cout << std::setw( width ) << n ;

And FWIW: width is volatile, and gets reset each time around;
the other values (like fill) aren't, and it is the fact that
they don't get reset which often causes problems.

(As an interesting exercise, compare:
printf( "%*d", ciel( log10( upper ), i ) ;
with:
std::cout << std::setw( ciel( log10( upper ) ) ) << i ;
Why does one work, and the other not:)?)
 
R

Robert Bauck Hamar

James said:
width = ciel( log10( upper ) ) ;
printf( "%*d", ciel( log10( upper ), i ) ;
std::cout << std::setw( ciel( log10( upper ) ) ) << i ;

I reckon ciel is a new way to spell ceil?
 
A

arnuld

I reckon ciel is a new way to spell ceil?

YES, it is "ceil". i just checked Stroustrup and found that it belongs
to <cmath> library. so here is the complete programme:

#include <iostream>
#include <cmath>
#include <iomanip>

int main()
{
std::cout << "Enter 2 numbers: ";
int v1, v2;
std::cin >> v1 >> v2;

int lower,upper;
if(v1 <= v2)
{
lower = v1;
upper = v2;
}
else
{
lower = v2;
upper = v1;
}

int counter = 0;
for(int i=lower; i <= upper; ++i)
{
if(counter > 9)
{
std::cout << std::endl;
counter =0;
}
double width = ceil(log10(upper));
std::cout << std::setw(width) << i << ' '; // inserts space
between 2 numbers
++counter;
}

std:: cout << "\nThank you Bantu ;-)" << std::endl;

return 0;
}

and output is really nicely formatted:

[arnuld@arch cpp]$ ./a.out
Enter 2 numbers: 9 200
9 10 11 12 13 14 15 16 17 18
19 20 21 22 23 24 25 26 27 28
29 30 31 32 33 34 35 36 37 38
39 40 41 42 43 44 45 46 47 48
49 50 51 52 53 54 55 56 57 58
59 60 61 62 63 64 65 66 67 68
69 70 71 72 73 74 75 76 77 78
79 80 81 82 83 84 85 86 87 88
89 90 91 92 93 94 95 96 97 98
99 100 101 102 103 104 105 106 107 108
109 110 111 112 113 114 115 116 117 118
119 120 121 122 123 124 125 126 127 128
129 130 131 132 133 134 135 136 137 138
139 140 141 142 143 144 145 146 147 148
149 150 151 152 153 154 155 156 157 158
159 160 161 162 163 164 165 166 167 168
169 170 171 172 173 174 175 176 177 178
179 180 181 182 183 184 185 186 187 188
189 190 191 192 193 194 195 196 197 198
199 200
Thank you Bantu ;-)
[arnuld@arch cpp]$

BUT what exactly this fragment does:

double width = ceil(log10(upper));
std::cout << std::setw(width) << i

???
 
M

Marcus Kwok

arnuld said:
BUT what exactly this fragment does:

double width = ceil(log10(upper));
std::cout << std::setw(width) << i

???

It looks at the larger value, then takes the log10 of it, and if
necessary, rounds it up to the next largest integer value. Taking the
log10 of the number will give you an indication of how many digits are
needed to display the number, though I think the formula given above has
an off-by-1 error. I would have used floor(log10(upper) + 1) in order
to catch the border cases.

For example,

n log10(n) ceil(log10(n)) floor(log10(n) + 1)
------ -------- -------------- -------------------
1 0 0 1
5 0.699 1 1
10 1 1 2
99 1.996 2 2
100 2 2 3
 
J

James Kanze

I reckon ciel is a new way to spell ceil?

A sort of heavenly fashion for us French speakers:). (Never
was much at spelling, anyway.)

Thanks for pointing it out.
 
J

James Kanze

It looks at the larger value, then takes the log10 of it, and if
necessary, rounds it up to the next largest integer value. Taking the
log10 of the number will give you an indication of how many digits are
needed to display the number, though I think the formula given above has
an off-by-1 error.

Could be. I just typed it in off the top of my head, without
too much thought.
I would have used floor(log10(upper) + 1) in order
to catch the border cases.
For example,
n log10(n) ceil(log10(n)) floor(log10(n) + 1)
------ -------- -------------- -------------------
1 0 0 1
5 0.699 1 1
10 1 1 2
99 1.996 2 2
100 2 2 3

Yup. Looks like there was an off by one error. Thanks for
pointing it out.

BTW: I threw out those two lines because they were the relevant
parts. I didn't expect them to be used as is. In particular,
I'd just automatically calculate the width once, at the top of
the loop, and reuse it each time through. (Come to think of it,
I'd probably store the width in an int as well, rather than as a
double.)
 
P

Puppet_Sock

std::cout << std::setw(width) << i << ' '; // inserts space
between 2 numbers

If you get keen, change it so it does not leave a
blank at the end of the line. It does not matter in
most cases for screen output, but to a file it would
leave one extra character per line.
Socks
 
Z

Zachary Turner

People can say what they will, but C++ streams are far easier
and more intuitive for just about any formatting.

Ease and intuition is partially a function of how much code it takes
to produce a desired effect. streams can take multiple lines of code
to achieve what printf can do with 4 or 5 characters. In an
environment where text processing is many, this can make the
difference between a function that's 15 lines of code and a function
that's 50 lines of code. I still have to look up printf format
specifiers for anything other than %d, but the fact that I end up with
something that I can eyeball and tell what it does in less than half a
second far outweighs any benefits I may attain by using streams. Just
my 2c.
 
J

James Kanze

Ease and intuition is partially a function of how much code it takes
to produce a desired effect.

That's why written Chinese is so much easier and intuitive than
written English, right.
streams can take multiple lines of code
to achieve what printf can do with 4 or 5 characters.

In addition to the type safety problems, and the lack of
extensibility, printf forces you to spread out the explicit
formatting throughout the code. (There are actually ways around
this, but I've never seen them used.) Typically, you never use
the standard manipulators in a real application; you use
application specific manipulators based on what you logically
want. So the day you decide that all of the FooBar values must
be output with one more digit precision, you change the FooBar
manipulator (one place in the code), and they all are output
with one more digit precision; with printf, you have to find all
of the printf which output a FooBar, and change the
corresponding format specifier.

In the end, which is more readable and maintainable:

fprintf( f, "%5.3 foo, %7.2 bar\n", fooValue, barValue ) ;
or
f << FooFmt << fooValue
<< " foo, "
<< BarFmt << barValue
<< " bar\n" ;

Of course, in C++, it would more often be:
fprintf( f, "%5.3 foo, %7.2 bar\n", obj.foo(), obj.bar() ) ;
vs:
f << obj << '\n' ;
In an
environment where text processing is many, this can make the
difference between a function that's 15 lines of code and a function
that's 50 lines of code.

Funny, I use iostream for generating text a lot, and I've almost
no functions which are more than 10 lines.
I still have to look up printf format specifiers for anything
other than %d, but the fact that I end up with something that
I can eyeball and tell what it does in less than half a second
far outweighs any benefits I may attain by using streams.

You mean you're able to look up the format specifiers in less
than a half a second? And recognize that "%5.3f" is the format
specifier for the way we currently output Foo?
 
Z

Zachary Turner

That's why written Chinese is so much easier and intuitive than
written English, right.
For people who live in China, I'm sure it's quite easy. The example
is poor, because even if you take someone who lives in neither china
nor an english speaking country, chances are they either use the roman
alphabet, a variant of the roman alphabet, or an alphabet similar to
chinese. That being said, printf() format specifiers aren't typically
written in chinese. I'm comparing:
a) n characters from the roman alphabet (printf)
to
b) 20n characters from the roman alphabet (streams)

In addition to the type safety problems, and the lack of
extensibility, printf forces you to spread out the explicit
formatting throughout the code.
And streams don't? You have to reinitialize the formatting after
every output. In some cases just specifying the formats takes an
entire line of code, before you even have a chance to output
surrounding text or the actual data.

I'm not mentioning type safety problems because streams are clearly
the winner there. Nothing's perfect, even printf (although it's
pretty close).

In the end, which is more readable and maintainable:

fprintf( f, "%5.3 foo, %7.2 bar\n", fooValue, barValue ) ;
or
f << FooFmt << fooValue
<< " foo, "
<< BarFmt << barValue
<< " bar\n" ;
Since you're comparing apples and oranges, I'll change the fprintf()
back to an orange.

fprintf(format, "%s foo, %s bar\n", FooFmt, BarFmt);
fprintf(f, format, fooValue, barValue);

Looks pretty easy to understand to me, and it solves the problem you
mentioned earlier about having to change every single printf()
statement in your code.

Alternatively, you can show the code that declares FooFmt and BarFmt
right about the stream output, and then we can compare it to your
original fprintf() statement.
You mean you're able to look up the format specifiers in less
than a half a second? And recognize that "%5.3f" is the format
specifier for the way we currently output Foo?

Much quicker than I can wade through poor stl documentation. and
typically the only thing I look up is the letter, not the precision
and width specifiers. So yes, it takes an instant to look it up.
 

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