Lab: Numeric Operations and Functions
Preparation
Before you start working through the exercises, you should do the following:
-
Introduce yourselves to one another and exchange preferred contact information for collaborating on Assignment 3 that is due next week.
-
Determine whether you or your partner’s name comes alphabetically before the other. The partner whose name is alphabetically first is assigned the role of the driver today and should share their screen. During the next lab, you and your partner will switch roles.
Exercise 1
In the reading, we learned how the //
operator performs integer division and throws away the remainder after dividing, and the %
operator returns the remainder. We will explore this in this exercise.
a. With your partner, predict what the following expressions will evaluate to.
>>> 5 // 3
>>> 5 % 3
>>> 10 // 2
>>> 10 % 2
b. Verify your predictions in the shell.
c. What do you think happens if we use negative numbers?
>>> -3 // 2
>>> -3 % 2
>>> 3 // -2
>>> 3 % -2
d. Verify your predictions in the shell.
e. Try running //
and %
on a variety of other numbers to see if it outputs what you expect.
Aside:
If you are curious, you can read more about these operators in the official Python reference. You can also read more about the %
operator in the Notes About Modulo at the bottom of the page. However, I recommend you go on to the next exercise first!
Exercise 2
In this exercise, we will write a program that is akin to how a vending machine computes how many coins to dispense to a customer when they need change.
a. Create a new file called make_change.py
and copy the following starter code into the file.
# A simple program that computes what coins to dispense
# in a vending machine
#
# Author:
# Titus Klinge, YOUR NAME(S) GO HERE
#
# 2023-01-01
def main():
print("This program computes how much of each coin")
print("denomination should be dispensed.")
change = int(input("Enter change (in cents): "))
quarters_needed = change // 25
change = change % 25
print("Here are", quarters_needed, "quarters.")
print("You still need", change, "more change.")
dimes_needed = change // 10
change = change % 10
print("Here are", dimes_needed, "dimes.")
print("You still need", change, "more change.")
nickels_needed = change // 5
change = change % 5
print("Here are", nickels_needed, "nickels.")
# Whatever is left over should be given in pennies
print("Here are", change, "pennies.")
main()
b. Try running the program on a variety of inputs to see what it is doing.
c. Try deleting the main()
at the very bottom and try running the program again. Does it still work?
d. What do you expect to happen if you end the program with two calls to main()
instead of just one?
Note: Putting the entry point of your program inside a main function is required in most languages but not required in Python. Many programmers think it is good practice to do so, however, it requires that you actually call the function exactly once after everything is defined.
e. Modify your program so that instead of taking the input as an int
representing cents, it takes a float
representing dollars.
Hint: You only need to modify one line of code in this step! (The very first one in main
.) Think about how you can convert a float
like 1.34
into an int
of 134
.
f. Test your modified program on a variety of float
inputs until you are confident it is correct.
g. Modify your program so that it also can give dollar bills back to the customer.
Hint: This requires computing a dollars needed number before computing how many quarters you need.
Exercise 3
We discussed how int
s are precise and can be arbitrarily large, but float
s are only approximate and there are limits to what numbers they can represent.
a. Try experimenting with large integers by typing expressions like the following into the shell. (Remember that 2 ** 3
computes “two raised to the third power.”)
>>> 2 ** 100
>>> 2 ** 1000
>>> 2 ** 10000
b. Now try doing the same except with floats.
>>> 2.0 ** 100
>>> 2.0 ** 1000
>>> 2.0 ** 10000
c. We know that if you take the square root of a number, then square it, we should get the same number back. Let’s try this out. Try the following commands in the shell.
>>> import math
>>> x = math.sqrt(2)
>>> x * x
Note:
You should always keep in mind that float
s are limited in the numbers they can represent and will always accumulate errors!
d. What do you think happens if you take the sqrt
of a negative number in Python? Try it!
>>> x = math.sqrt(-2)
Exercise 4
The round
function rounds a decimal number to the nearest whole number.
a. Play around with the round
function by executing it on the following inputs.
>>> round(5.7)
>>> round(5)
>>> round(5.0)
>>> round(-13.9)
>>> round(7.91227, 2)
>>> round(7.91227, 3)
>>> round(math.pi, 2)
b. Try to implement the round
functionality yourself without using it directly. In other words, write an expression that rounds a number to the nearest whole number without using round(...)
.
Hint:
The int(...)
function does something very similar to round(...)
. Think about how you could use int()
and the +
operator to do the same thing as round(...)
.
The expression will likely look like int(1.73 + ...)
where 1.73
is the number you want to round. Your expression should round correctly for all numbers other than ones like 0.5
(you may choose to round up or down on 0.5
).
c. Let’s go even further by rounding to certain decimal places! Create a new file called round.py
with the following starter code.
# A simple program that rounds a number to a certain number
# of decimal places
#
# Author:
# Titus Klinge, YOUR NAME(S) GO HERE
#
# 2023-01-01
def main():
num = float(input("Enter a float to be rounded: "))
precision = int(input("Enter the precision you want: "))
# rounded_num = ...
# print("Your number rounded is:", rounded_num)
main()
d. Uncomment the last two lines of code in the main()
function by deleting the #
in front of them. (Make sure that these lines of code line up horizontally with the first two lines of the main()
function.)
e. Finish writing the program by filling in the “…” of the rounded_num
definition. Remember that you cannot use round
directly—you must come up with your own expression for it. When you run your program, you should see the following:
Enter a float to be rounded: 17.37112
Enter the precision you want: 3
Your number rounded is: 17.371
Hint:
How can you modify your idea from part b. to work with decimal places? You might want to use /
, *
, and **
operations here to “shift” the decimal place, round to a whole number, and then shift back.
f. Test your program on a variety of inputs until you are satisfied that it is correct.
Exercise 5
Sometimes it is useful to add and subtract clock times together. For example, if you are observing a runner’s lap time, you might measure the start time and the end time and subtract them.
a. Write a program called subtract_times.py
that asks the user for four integer inputs:
- The minutes of the start time
- The seconds of the start time
- The minutes of the end time
- The seconds of the end time
It should then compute the difference of the end time and start time and output the elapsed time in minutes and seconds. (Note that the seconds should be a value between 0 and 59! Therefore simply subtracting minutes and seconds will not work.)
Hint:
Use the %
and //
operators similar to Exercise 2.
b. Test your program on a variety of inputs.
How to Submit Your Lab Work
- Once you are finished with the lab, you should go to codePost and log into your account with your Drake email address.
- Go to the CS 65 course.
- Go to Lab 3 and upload your
make_change.py
file. - After you submit, open up your submission again. In Partners tab at the top of the submissions window, there will be a link. Send this link to your partner and have them open it while logged into their account.
- If all goes well, you should see both yourself and your partner as authors of the submission.
Finished Early?
If you have extra time, continue working on Assignment 3.
Notes About Modulo
The %
operator is called the modulo operator. This operation is very similar to computing the remainder of integer division. In fact, if you have two positive integers a
and b
, then a % b
will always compute the remainder of a // b
. This is how %
is most commonly used in programming.
However, it is important to note that %
does NOT compute the remainder on negative numbers. Below is a table of the values of n % k
for various values of n
and k
.
n |
… | -4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | … |
---|---|---|---|---|---|---|---|---|---|---|---|
n % 2 |
… | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | … |
n % 3 |
… | 2 | 0 | 1 | 2 | 0 | 1 | 2 | 0 | 1 | … |
n % 4 |
… | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | … |
The repeating pattern is important to take note of. If you explore more advanced mathematics, you’ll encounter more uses of modulo than just remainder. In this class, just be careful when using %
on numbers that can be negative.