Consider the following traditional Christmas song:
On the first day of Christmas
My true love gave to me
A partridge in a pear tree.
On the second day of Christmas
My true love gave to me
Two turtle doves
And a partridge in a pear tree.
On the third day of Christmas
My true love gave to me
Three French hens,
Two turtle doves,
And a partridge in a pear tree.
And so on, through the twelfth day of Christmas. Let's count a partridge in a pear tree as constituting a single present, so that on the first day, my true love gave me one present. Similarly on the second day my true love gave me three presents, on the third day six presents, and so on.
If I wanted to figure out how many presents I received on a particular day, the most straightforward approach would be to add them all up. Section 1.4 in our textbook explains a slicker approach based on visualizing the presents that day as arranged in a triangle. The triangle can fit together with another equal-sized triangle to form a rectangle. This allows a direct calculation of the number of presents on day n as n(n+1)/2. If all is well, both approaches ought to give the same answers.
Suppose we instead want to figure out my total haul for the entire Christmas season. Added up over all twelve days, how many presents did my true love give me? The geometric approach still works, if you can visualize three-dimensional shapes well enough. You can lay down the big triangle from day 12, stack on top of it a smaller triangle from day 11, and so forth on up to form a pyramid. If you figure out how many of those pyramids fit together to form a rectangular solid, and how long each of the three sides of the rectangular solid are, you can derive a formula for the total number of presents. But I don't recommend you try this, at least without having a more straightforward calculation to check your work against, because most humans aren't very good at rotating pyramids around in their heads. So let's write a straightforward program that totals up the answer. While we're at it, we can compare the two approaches in the single-day case as well.
You are to do this project individually.
Open up a new window in Idle and type in a definition for a procedure, presentsOnDay
. The procedure
should have one parameter, specifying which day of Christmas you are interested in. (For example, you would pass
in 12 to find out how many presents my true love gave me on the 12th day of Christmas.) Be sure to use a descriptive
name for the parameter. Your procedure should return the overall number of presents for the specified day. Use the
accumulator pattern to calculate the answer by adding up all the different kinds of presents. Save your program in
a file called xmas.py
.
Use Idle's "Run Module" command from the Run menu, or equivalently press the F5 key. If Idle reports any syntax
errors in your program, fix them. When you get past that hurdle, use the Python Shell window of Idle to try your
presentsOnDay
procedure out for days 1, 2, and 3. Make sure your procedure gives the same answers as
in the overview section; if not, fix it. Once you are confident that the procedure is working, find out how many
presents are on day 12.
Add a second procedure in the same file, this one called presentsThroughDay
. It should again have a
single parameter, this time indicating the last day number you are interested in. For example, if you passed in
the number 12, it would indicate you were interested in all days up to and including day 12. The procedure should
return the total number of presents, added up across all the days. Use the accumulator pattern to do this adding
up across the days. Each time your procedure needs to find the number of presents on a particular day, it should
use presentsOnDay
.
Make sure your presentsThroughDay
procedure produces the right answers if you ask it about just the
first day, or the first two days, or the first three days. Fix any errors you discover. Then find out the total
number of presents my true love gave me over the full 12-day Christmas season.
One question about an algorithm is whether it produces the correct result. But another question is how well it
scales up to larger problem sizes. My true love actually is generous enough to give me presents even outside
the Christmas season. Get a sense for how well the straightforward algorithm using two accumulations can accommodate
this by trying presentsThroughDay
out with values such as 10, 100, and 1000. How far do you have the
patience to go? If a computation is taking too long, you can stop it using the control-c key combination. (For
reference, my parents have been married for over 12775 days. I am still in search of my true love, so I guess zero days)
In the xmas.py
window, select your presentsOnDay
procedure definition by dragging
the mouse through it. Then use the "Comment Out Region" command from the Format menu, or equivalently the
control-3 key combination. This should put ##
characters at the beginning of each line. In
Python, anything from a #
character to the end of the line is a "comment," that is, not an actual
part of the program that will get run. So effectively you have removed this procedure definition by turning it
into nothing but comments. The advantage is that it is still visible and can be uncommented if you ever want
it back. Now add the following definition to the file:
def presentsOnDay(day): return day*(day+1)//2
Now if you go back to trying presentsThroughDay
with large numbers of days, you should find that
it scales up much better but still gives the same answers. With the new version, how large a number of days do
you have patience for?
You will be submitting your code using Moodle; click on the following link for instructions on submitting code using Moodle. For this project, you will need to submit the following 2 files (with the following recommended names):
You will earn one point for each of the following accomplishments:
You have written a contract and docstring for the presentsOnDay
procedure.
Your presentsOnDay
procedure returns an answer.
Your presentsOnDay
procedure uses the accumulator pattern to calculate its answer.
Your presentsOnDay
procedure calculates the correct answer.
Your presentsOnDay
procedure uses a descriptive parameter name.
You stated the number of presents for day 12.
You have written a contract and docstring for the presentsThroughDay
procedure.
Your presentsThroughDay
procedure returns an answer.
Your presentsThroughDay
procedure uses the accumulator pattern to calculate its answer.
Your presentsThroughDay
procedure uses the presentsOnDay
procedure.
Your presentsThroughDay
procedure calculates the correct answer.
Your presentsThroughDay
procedure uses a descriptive parameter name.
You stated the total number of presents through day 12.
Your paragraph explains what procedure has two different versions.
Your paragraph makes it clear whether you compared the two versions directly, or in the context of their use by some other procedure. (In the latter case, you make clear which other procedure.)
Your paragraph indicates in a general way how the speeds compared. For example, you might say "I didn't notice any difference for parameter values up to ..., but by the time I got to ..., ... was taking several seconds whereas ....."
Your paragraph gives the largest value you were willing to wait for with the slow algorithm and approximately how long it took. (Seconds? Minutes? Tens of minutes?)
Your paragraph gives the largest value you were willing to wait for with the fast algorithm and approximately how long it took. (Seconds? Minutes? Tens of minutes?)
Your paragraph reports on whether the two algorithms computed the same answers in the cases where you tested both.
Your paragraph meets general expectations for college-level writing.