# Accelerated C++: Exercise 3-2

Discussion in 'C++' started by Xernoth, Apr 12, 2007.

1. ### XernothGuest

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

Xernoth, Apr 12, 2007

2. ### zeppeGuest

Xernoth wrote:

> 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

zeppe, Apr 12, 2007

3. ### JonasGuest

"Xernoth" <> wrote in message
news:...
> 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;

>
> 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

--
Jonas

Jonas, Apr 13, 2007
4. ### XernothGuest

On Apr 12, 11:44 pm, zeppe <>
wrote:
> 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.

Xernoth, Apr 13, 2007
5. ### XernothGuest

Jonas wrote:
> A vector of double called integerSet...? Better
>
> std::vector<int> integerSet;

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>.

Xernoth, Apr 13, 2007
6. ### JonasGuest

"Xernoth" <> wrote in message
news:...
> Jonas wrote:
>> A vector of double called integerSet...? Better
>>
>> std::vector<int> integerSet;

>
> 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.

--
Jonas

Jonas, Apr 13, 2007
7. ### XernothGuest

On Apr 13, 4:23 pm, "Jonas" <> wrote:
> 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.

Xernoth, Apr 13, 2007
8. ### Amit GuptaGuest

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.

Amit Gupta, Apr 15, 2007
9. ### Andrew KoenigGuest

"zeppe" <> wrote in message
news:461eb659\$...

> 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.

Andrew Koenig, Apr 15, 2007
10. ### James KanzeGuest

On Apr 15, 7:55 am, "Andrew Koenig" <> wrote:
> "zeppe" <> wrote in message

> news:461eb659\$...

> > 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.

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.

--
James Kanze (Gabi Software) email:
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

James Kanze, Apr 15, 2007
11. ### James KanzeGuest

On Apr 15, 7:16 am, "Amit Gupta" <> wrote:
> 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.

--
James Kanze (Gabi Software) email:
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

James Kanze, Apr 15, 2007