Accelerated C++: Exercise 3-2

X

Xernoth

Hi,

This is my first post here, so please be gentle. I've been studying c+
+ by mostly using the book Accelerated C++ by Andrew Koenig and
Barbara E. Moo.

So far, I've been picking things up all right, and I've come to an
exercise 3-2 that requires the following:
3-2. Write a program to compute and print the quartiles (that is, the
quarter of the numbers with the largest values, the next highest
quarter, and so on) of a set of integers.

After researching what quartiles are, and using the method defined
here: http://www.statcan.ca/english/edu/power/ch12/range.htm (as from
what I've read, there are different methods used for computing lower
and upper quartiles) I've been able to write a console program that
seems to calculate correctly. However, I would like advice, from a
programming perspective, on what I could improve.

For those who haven't read the above book, it has a unique way of
introducing C++, as the first chapter jumps straight into the use of
strings, so a lot of basics, like use of functions and so on, have not
been covered as yet.

My code is as below:

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
std::cout << "Enter a range of integers followed by 'end': ";

std::vector<double> integerSet;

int x;
while (std::cin >> x)
integerSet.push_back(x);

sort(integerSet.begin(), integerSet.end());

typedef std::vector<double>::size_type vector_Size;

vector_Size size = integerSet.size();
vector_Size mid = size / 2;
double median;
double lowerQuartile;
double upperQuartile;

median = size % 2 == 0 ? (integerSet[mid] + integerSet[mid-1]) / 2
: integerSet[mid];

vector_Size midlq = mid / 2;
lowerQuartile = mid % 2 == 0 ? (integerSet[midlq] +
integerSet[midlq - 1]) / 2
: integerSet[midlq];

vector_Size miduq = size - midlq;
upperQuartile = mid % 2 == 0 ? (integerSet[miduq] +
integerSet[miduq - 1]) / 2
: integerSet[miduq - 1];

int unsigned i = 0;
std::cout << "Ordered Data: ";
while (i != size)
{
std::cout << integerSet << " ";
i++;
}
std::cout << std::endl;
std::cout << "Median: " << median << std::endl;
std::cout << "Lower Quartile: " << lowerQuartile << std::endl;
std::cout << "Upper Quartile: " << upperQuartile << std::endl;

return 0;
}

Thanks
 
Z

zeppe

Xernoth said:
For those who haven't read the above book, it has a unique way of
introducing C++, as the first chapter jumps straight into the use of
strings, so a lot of basics, like use of functions and so on, have not
been covered as yet.

The program seems well written! Just a note: it's useless to typedef the
std::vector<double>::size_type: use directly std::size_t.

And, of course you'll have noticed, your program performs three times
the same action, as the quartiles can be viewed as the medians for the
upper and lower half of the distribution. Once you'll start studying the
function, it would be interesting for you to try implementing a
function that do this job and calling it three times.

Regards,

Zeppe
 
J

Jonas

Xernoth said:
Hi,

This is my first post here, so please be gentle. I've been studying c+
+ by mostly using the book Accelerated C++ by Andrew Koenig and
Barbara E. Moo.

So far, I've been picking things up all right, and I've come to an
exercise 3-2 that requires the following:
3-2. Write a program to compute and print the quartiles (that is, the
quarter of the numbers with the largest values, the next highest
quarter, and so on) of a set of integers.

After researching what quartiles are, and using the method defined
here: http://www.statcan.ca/english/edu/power/ch12/range.htm (as from
what I've read, there are different methods used for computing lower
and upper quartiles) I've been able to write a console program that
seems to calculate correctly. However, I would like advice, from a
programming perspective, on what I could improve.

For those who haven't read the above book, it has a unique way of
introducing C++, as the first chapter jumps straight into the use of
strings, so a lot of basics, like use of functions and so on, have not
been covered as yet.

My code is as below:

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
std::cout << "Enter a range of integers followed by 'end': ";

std::vector<double> integerSet;

A vector of double called integerSet...? Better

std::vector<int> integerSet;


int x;
while (std::cin >> x)
integerSet.push_back(x);

sort(integerSet.begin(), integerSet.end());

typedef std::vector<double>::size_type vector_Size;

Use std::size_t instead.

vector_Size size = integerSet.size();
vector_Size mid = size / 2;
double median;
double lowerQuartile;
double upperQuartile;

median = size % 2 == 0 ? (integerSet[mid] + integerSet[mid-1]) / 2
: integerSet[mid];

If you changed the declaration of integerSet to vector<int> above, you need
to divide by 2.0 instead of 2 to get floating point division:

median = size % 2 == 0 ? (integerSet[mid] + integerSet[mid-1]) / 2.0 :
integerSet[mid];

The same applies below.
vector_Size midlq = mid / 2;
lowerQuartile = mid % 2 == 0 ? (integerSet[midlq] +
integerSet[midlq - 1]) / 2
: integerSet[midlq];

vector_Size miduq = size - midlq;
upperQuartile = mid % 2 == 0 ? (integerSet[miduq] +
integerSet[miduq - 1]) / 2
: integerSet[miduq - 1];

int unsigned i = 0;
std::cout << "Ordered Data: ";
while (i != size)
{
std::cout << integerSet << " ";
i++;
}


While the above loop works, a more idiomatic way would be

for (std::size_t i = 0; i < size; i++) {
std::cout << integerSet << " ";
}

Or, using an iterator:

for (std::vector<int>::iterator iter = integerSet.begin(); iter !=
integerSet.end(); iter++) {
std::cout << *iter << " ";
}

std::cout << std::endl;
std::cout << "Median: " << median << std::endl;
std::cout << "Lower Quartile: " << lowerQuartile << std::endl;
std::cout << "Upper Quartile: " << upperQuartile << std::endl;

return 0;
}


Apart from that, looking good :)
 
X

Xernoth

The program seems well written! Just a note: it's useless to typedef the
std::vector<double>::size_type: use directly std::size_t.

Thanks for that, I'm not very familiar with the uses of std::size_t,
but I'll review and see how it can be implemented in the current
code.
 
X

Xernoth

Jonas said:
A vector of double called integerSet...? Better

std::vector<int> integerSet;

I thought about this, and I believe initially I had it set to <int>,
but for some reason changed it to double at one point because
something wasn't calculating correctly; though I doubt that would of
been the cause of an incorrect calculation.
I've not been great with naming conventions for variables, so I can
see that integerSet can be misleading if set to <double>.

Thanks to both for your comments and suggestions.
 
J

Jonas

Xernoth said:
I thought about this, and I believe initially I had it set to <int>,
but for some reason changed it to double at one point because
something wasn't calculating correctly; though I doubt that would of
been the cause of an incorrect calculation.

It was probably not incorrect, just the result of an unexpected integer
division. Example: After the execution of

double result = 5 / 2;

the variable "result" holds the value 2.0, not 2.5 as one might think. This
is because you perform an integer division, which yields an integeger that
is then converted to a double. In your code, you divide an element from
integerSet with 2, which is an integer division. If one of the operands is a
floating point type, then the operation becomes a floating point operation.
So

double result = 5 / 2.0;

yields the result 2.5.
 
X

Xernoth

If one of the operands is a
floating point type, then the operation becomes a floating point operation.
So

double result = 5 / 2.0;

yields the result 2.5.

Ah, thanks for clarifying that. I only had a quick read in regard to
floating point arithmetic. I'll need to review that more in-depth, as
that could be causing inaccuracies with future calculations.
 
A

Amit Gupta

My 2 cents..

Throw your book into some trash-can and never look back.

You first need to understand why std::size_t and the one you defined
are same. There is nothing like reviewing it. Second, learn floating
point arithmetic before trying a double variable.

Better yet, please, first learn the language before you code using
that. I think longer term, it will be very helpful.
 
A

Andrew Koenig

The program seems well written! Just a note: it's useless to typedef the
std::vector<double>::size_type: use directly std::size_t.

Useless? Why? std::vector<double>::size_type is an unsigned type that has
room to hold the number of elements in any vector<double>. It is not
difficult for me to imagine machine architectures in which thie type differs
from std::size_t, and I can see no obvious reason why std::size_t would be
preferable on such architectures.

I think that using an object of std::vector<double>::size_type to represent
an index of a std::vector<double> object is an example of saying what you
mean.
 
J

James Kanze

Useless? Why? std::vector<double>::size_type is an unsigned type that has
room to hold the number of elements in any vector<double>. It is not
difficult for me to imagine machine architectures in which thie type differs
from std::size_t, and I can see no obvious reason why std::size_t would be
preferable on such architectures.

The standard says that vector<>::size_type comes from the
allocator, and that in the default allocator, it must be a
size_t. IMHO, whether to use std::vector<double>::size_type or
simply size_t is largely a matter of style.

If you're using typedef's, the issue becomes a little less
subjective: if I've something like:

typedef std::vector< double > VectDbl ;

then VectDbl::size_type will automatically adjust if I change
the typedef to use a user defined allocator; size_t won't (and
could be wrong).
I think that using an object of std::vector<double>::size_type to represent
an index of a std::vector<double> object is an example of saying what you
mean.

A very verbose way:). That's why I say it is a matter of
style. It is certainly more explicit; you're not just using
size_t, you're using a specific type because it is the size_type
of std::vector.
 
J

James Kanze

My 2 cents..
Throw your book into some trash-can and never look back.

The book he's using (Koenig's "Accelerated C++") is generally
recognized as one of the best for beginners. I'm pretty sure
that the book didn't tell him to switch to double anytime he's
unsure of a result.
You first need to understand why std::size_t and the one you defined
are same.

And you need to understand why in most cases, one might prefer
what he defined. It's a question of style, but some styles are
preferred over others.
There is nothing like reviewing it. Second, learn floating
point arithmetic before trying a double variable.

That, of course, is very good advice. Rarely taken, but very
good anyway.
 

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,968
Messages
2,570,152
Members
46,697
Latest member
AugustNabo

Latest Threads

Top