Você está na página 1de 3

Math 273: Data Structures and Algorithms

2016-04-25

Project 05: A Timer Class

This project requires that you define a Timer class for computing running times of algorithms. A Timer works like a stopwatch. It can be started, stopped, or reset, and it has
two states, STOPPED and RUNNING. The start, stop, and reset operations may depend
on the Timers state.
Most hand-held stopwatches have one or two buttonsone for toggling start/stop,
and possibly another for reset. However, we will assume our Timer class has three virtual
buttons, one for starting, one for stopping, and one for reset.
For example, if Bubba starts his Timer at noon, then presses its stop button at 12:02:37,
his Timer reads 2:37. Later if Bubba presses the start button at 12:15:30 and then presses
stop at 12:15:40, his Timer reads 2:47. Pressing start while the watch is running has no
effect, and pressing stop while the watch is not running has no effect either.
To time an algorithm, start a timer immediately before its invocation, and stop the
timer immediately after it finishes. Here is an example timing std::sort() on a large array.
std::vector<int> twos(1000000,2); // one million 2's
math273::Timer<std::chrono::milliseconds> stopwatch;
stopwatch.start();
std::sort(twos.begin(), twos.end());
stopwatch.stop();
std::cout << "One million twos were sorted in " << stopwatch.read()
<< " milliseconds.\n";

Timer is a template class whose template argument is its units. So the stopwatch above
measures time in milliseconds. Its read() member returns the current readout in the appropriate units. On my laptop this says One million twos were sorted in 29 milliseconds.
Library <chrono>
C++ already has timing facilities in its <chrono> library, but you will make them easier to
use. All are defined in namespace std::chrono. There are three types of clocks defined by
classes system_clock, steady_clock, and high_resolution_clock. The system_clock models the computer system clock, so it may skip abruptly with daylight savings time or leap
seconds. On the other hand, a steady_clock is a strictly monotonic clock which is unaffected by changes in the system clock. The high resolution clock is capable of measuring
time in ridiculously small units, depending on the hardware.
1

All clock classes have member now() which returns a time_point, and the difference
between time points has type duration. These classes are templates which, when used
together, must have compatible template arguments (very complicated). For convenience,
the classes with template arguments are typedef-ed inside the clock class. For example,
clock::time_point begin, end;
clock::duration elapsed;
begin = clock::now();
std::sort(twos.begin(), twos.end());
end = clock::now();
elapsed = end - begin;
std::cout << "One millions twos were sorted in "
<< std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count()
<< " milliseconds.\n";

The duration_cast converts a duration object to another with appropriate units. Member
function count() returns the amount of time measured in the appropriate units. Conveniently there are types for hours, minutes, seconds, milliseconds, microseconds, and
nanoseconds (std::chrono::hours, std::chrono::minutes, etc.). Moreover, the obvious arithmetic operations can be done with time_points and durations.
Here is an example of a complete program which prints Hello! for 237 milliseconds.
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main()
{
do {
std::cout << "Hello!\n";
time_elapsed = steady_clock::now() - start_time;
} while (duration_cast<milliseconds>(time_elapsed).count() < 237);
return 0;
}

Your Timer class will make writing such code slightly more convenient, as follows.
#include "Timer.h"
#include <iostream>
int main()
{
math273::Timer<std::chrono::milliseconds> timer;
timer.start();
do {
std::cout << "Hello!\n";
} while (timer.read() < 237);
return 0;
}

The Timer Class

Your Timer class is a template class which expects exactly one template argument, either
std::chrono::hours, std::chrono::minutes, std::chrono::seconds, std::chrono::milliseconds,
std::chrono::microseconds (millionths of a second), or std::chrono::nanoseconds (billionths
of a second). Define the class in namespace math273, so a proper declaration would be
#include <chrono>
math273::Timer<std::chrono::microseconds> t;

Class Timer must have member functions reset(), start(), stop(), and read(), which
do exactly as their names describe. All are void except for read() which returns a ssize_t
(signed size t). Moreover, a Timer object must always be in either one of two states,
STOPPED or RUNNING, and its member functions must be defined appropriately for
each state. For example, if a Timer is in state STOPPED, its member stop() should do
nothing. (Suggestion: Use an enum for the state.) The state of a Timer should be an
internal (private) detail. You should list all possibilities for each function for each state
before writing your program.
You can subtract time_points as shown above, and you can also add durations using
operator+ or even operator+=. For example,
total_time += std::chrono::steady_clock::now() - saved_time_point;

You must use a steady_clock to measure time in your Timer class.

Files to Submit
Write the complete implementation of the Timer class in a file Timer.h. Submit this file
before 11:55pm on Friday, May 6. Write your own main.cpp for testing. Be sure to test
use of stop() and start() in both states. You might also test all the sorting algorithms you
have written and output results in a table as follows.
Sorting Algorithm Running Times (seconds)
----------------------------------------.
n
---------10000
100000
1000000
10000000
100000000

bubble
------

selection
---------

insertion
---------

merge
-----

heap
-----

quick
-----

std::sort
---------

(You can create files with random data using the random number generator interface in
<random>, which was described in class earlier.)
3