The statistician is a class that is designed to keep track of simple statistics about a sequence of real numbers. There are two member functions that you should understand at an informal level before you proceed any further. The prototypes for these two functions are shown here as part of the statistician class declaration:
class statistician { public: ... void next(double r); double mean( ) const; ... };
The member function "next" is used to give a sequence of numbers to the statistician one at a time. The member function "mean" is a constant member function that returns the arithmetic mean (i.e., the average) of all the numbers that have been given to the statistician.
Example: Suppose that you want a statistician to compute the mean of the sequence 1.1, 2.8, -0.9. Then you could write these statements:
// Declares a statistician object called s statistician s; // Give the three numbers 1.1, 2.8 and -0.9 to the statistician s.next(1.1); s.next(2.8); s.next(-0.9); // Call the mean function, and print the result followed by a carriage return cout << s.mean( ) << endl;
The output statement will print 1.0, since 1.0 is the mean of the three numbers 1.1, 2.8 and -0.9.
Once you understand the workings of the next and mean member functions, you
can look at the complete specification of the statistician class, which is
in the file
stats.h
.
Notice that the statistician class in this file is part of a
namespace called main_savitch_2C
. You should use
this namespace for your statistician.
In this file you will find a
precondition/postcondition contract for all the statistician's member
functions, including:
statistician operator +(const statistician& s, const statistician& t);
statistician operator *(double scale, const statistician& s);This is not a member function. The result of a multiplication such as 2*s is a new statistician that looks as if it had been given all the numbers of s, multiplied by the constant 2.
==
are member functions either.
The result of s+t is a new statistician that looks as if it had been given
all the numbers of the sequence for s, followed by all the numbers of the
sequence for t.
==
function returns true if the two statistician objects,
s1 and s2 have exactly the same states. Otherwise it returns false.stats.h
.
Notice how the private member variables are being
used to keep track of information about the statistician's sequence of
numbers. The statistician does
NOT keep track of all the numbers in the sequence. There is no
need to do so, and trying to do so can get you into trouble. Instead, it
keeps track of only the information that is relevant to its member
functions: How many numbers have been seen? What is the sum of those
numbers? If you have seen at least one number, then what are the smallest
and largest numbers that you've seen so far?
Be careful about how you set the private member variable that keeps track of the smallest number. My suggestion is that you do NOT have the constructor initialize this member variable (because when the constructor does its work, there have not yet been any numbers, so there is no smallest number). But part of the work of the "next" function is to correctly maintain the private member variables. This means that the first time that the next function is called, it should set the private member variable that keeps track of smallest values. Later, if next is called again with a smaller number, then the next function will change the member variable that is keeping track of the smallest value. (You'll have a similar process for the member variable that's keeping track of the largest value).
void statistician::next(double r) { // This is just a stub, to be implemented later. }A first implementation might have only:
Even with just stubs, your stats.cxx file will correctly
compile and link with the interactive test program,
stattest.cxx
.
For example, if you are using the g++ compiler, you would compile
and link the stattest program with these three commands:
g++ -Wall -c stats.cxx g++ -Wall -c stattest.cxx g++ stattest.o stats.o -o stattest
ANSWER: No, leave those preconditions in there! Instead, you must find out where one of your functions is violating a precondition. Here is a typical example: Some students started by implementing the operator + along these lines:
bool operator + (const statistician& s1, const statistician& s2) { statistician answer; if (s1.minimum( ) < s2.minimum( )) { answer.tiniest = s1.minimum( ); } else { answer.tiniest = s2.minimum( ); } ... }The problem with this implementation is that the operator + is allowed to be called even if s1 or s2 or both are empty. In such a case, the function will eventually get to the test (s1.minimum( ) < s2.minimum( )) and...assertion failed! because you cannot call minimum for an empty statistician.
How do you fix this problem? In your operator + you should start with a test to see whether s1 or s2 is empty (and handle those cases in a way that does not call minimum() or maximum() ).
MORAL: The functions you write can call other functions, but they must be careful to not violate preconditions.
ANSWER: There are several solutions. One idea is to not initialize them at all. In this case, you must be careful to make sure of two things: (A) When the first number is given to the next function, it puts that first number into both of those member variables. (B) None of the other functions ever try to use tiniest or largest for an empty statistician.
ANSWER: Well, any function that accesses tiniest, largest, minimum() or maximum() probably needs a special case. Sometimes the special case can be simple. For example, the start of my operator * has a special case:
if (s.length( ) == 0) return s;...now the rest of my code doesn't need to worry about s being empty.
ANSWER: Here's an example: Suppose that a statistician x has been given three numbers 10, 20 and 40. Then we execute the statement y = -1*x; The statistician y must act as if it had been given -10, -20 and -40 so y.minimum() will be -40 and y.maximum() will be -10.
ANSWER: Make sure that all the code in your stats.cxx is in the namespace main_savitch_2C (look at the similar example of the point class on page 63).
ANSWER: See the answer to the previous question.
ANSWER: Yes. At this point of the game, about 60% of warnings are errors. Spotting the cause of the warnings is an important part of learning about C++.
ANSWER: Not much of that is needed until a function gets longer than 10-15 lines.
// Problem 1: s1.length( ) = s2.length( ) + s3.length( ); // You can't assign to a function such as length. Try assigning to // s1.count (the variable) instead. // Problem 2: if (s1.length == s2.length) // You have to call the function. Try (s1.length() == s2.length()).