
Week 5: In-Class#
Demo#
Demo 5.1: Fall Duration#
The distance traveled by an object falling from rest is given by the formula
where \(s\) is the distance traveled (in meters), \(t\) is the duration of the fall (in seconds), and \(g\) is the gravitational acceleration on Earth, equal to \(9.81\mathrm{m}/\mathrm{s}^2\).
Pen & Paper
For heights of 100 m and 24 m, calculate the fall duration.
If you do not have a pen or paper at hand, you can type your answers here:
| Height | 100 meters | 24 meters |
|---|---|---|
| Fall duration |
Demo
Write a function fall_duration that takes as input the fall distance traveled (in meters) and returns the fall duration (in seconds).
Demo 5.2: Customized Greeting#
It is a custom to greet people differently depending on the time of day. We use a convention that morning starts at 4:30, and lasts until 12:00 when afternoon begins. At 17:30 evening starts, and night starts at 23:00. Morning, afternoon, evening, and night are marked with green, red, light blue, and dark blue colors, respectively, in the figure below.
We want to determine a suitable greeting based on the time of day: Good morning!, Good afternoon!, Good evening!, or Good night!. Each time period includes its starting time but excludes its ending time. For example, 4:30 is morning, but 12:00 is afternoon.
Pen & Paper
According to the convention above, write down what the greeting should be for the following times of day: 7:00, 12:30, 18:15, 23:45, and 3:15. Also, determine the correct greeting for times just before and just after each boundary. Finally, notice that night includes times before midnight and after midnight. Write down the time for both these periods.
Demo
Write a function customized_greeting that returns a polite greeting based on the time of day. The function should take two arguments: hours and minutes.
The argument hours is the hour of the day given in 24-hour format, so it is an integer between 0 and 23. The argument minutes is the minutes of the hour, given as an integer between 0 and 59. The function should return the correct greeting as a string, for example, "Good morning!".
Coding Practice#
Code 5.3: Function Testing (Buddy-Exercise)#
Writing tests for functions often involves just as much work as writing the functions themselves and is just as important. You can write tests before writing the function. You can even write tests for a function that you do not yet know how to write. For example, suppose a function count_a should count how many times the lowercase letter a appears in a string. You have not yet learned how to write such a function, but you can already write tests which check, whether the function works as intended.
For this, you can create a dummy version of the function that always returns the same value, for example, 0. Then, you can write and run tests. Since the dummy version does not do what it is supposed to, the tests will fail. Once you have the correct function, it should pass the tests.
Below you can see a dummy version of the function count_a and some tests. Run it to see whether all tests pass or not.
def count_a(s):
return 0
test1 = count_a("banana") == 3
test2 = count_a("apple") == 1 # starting with 'a'
test3 = count_a("drape") == 1 # containing 'a'
test4 = count_a("milla") == 1 # ending with 'a'
test5 = count_a("cherry") == 0 # no 'a'
test6 = count_a("") == 0 # empty string
test7 = count_a("Aardvark") == 2 # case sensitivity
test8 = count_a("aaaaaa") == 6 # all 'a'
all_tests_passed = (test1 and test2 and test3 and test4 and test5 and test6
and test7 and test8)
print("All tests passed:", all_tests_passed)
if not all_tests_passed:
print("Individual test results:", test1, test2, test3, test4, test5, test6,
test7, test8)
As you can see, a dummy version may pass some tests by chance, but it will fail others. This is why it is useful to test a function with several inputs that cover different situations. If a function passes all the tests, this is evidence that it may work correctly, but additional tests can give you more confidence.
For this buddy exercise, we will practice writing functions and tests using Code 5.4 (Number Digits) and Code 5.5 (Next Even). Read both exercises first. Then follow the instructions below with your buddy.
Look at Code 5.4 and write the
number_digitsfunction in thenumber_digits.pyfile.Create the
next_even_test.pyfile and write a dummy version of thenext_evenfunction in it. The dummy function should always return0.Look at Code 5.5 and write tests for the
next_evenfunction in thenext_even_test.pyfile.
Look at Code 5.5 and write the
next_evenfunction in thenext_even.pyfile.Create the
number_digits_test.pyfile and write a dummy version of thenumber_digitsfunction in it. The dummy function should always return an empty string.Look at Code 5.4 and write tests for the
number_digitsfunction in thenumber_digits_test.pyfile.
Now send the files to each other, so that you both have all four files, and place the four files in the same folder. Together, test both functions using the following two strategies.
Strategy 1: Put the function and its test in the same file
For each function, put the function and its test in the same file. You can either add the tests below the real function or copy the real function over the dummy function in the test file. Then run the file containing the function and its tests.
Strategy 2: Import the function into the test file
Instead of copying the real function into the test file, you can import it. This works because the function file and the test file are in the same folder. For example, to test next_even, add this line to next_even_test.py:
from next_even import next_even
Delete the dummy next_even function from the test file after adding the import, and then run the test file.
Use both strategies to test both functions. If a function does not pass the tests, debug the function and the tests together.
Code 5.4: Number Digits#
Write a function number_digits that takes a positive integer as input and returns the number of digits in the number.
The test for this function should contain at least six different positive integers with varying numbers of digits.
Hint
You can convert the integer to a string and then use the len function.
Code 5.5: Next Even#
You should write a function next_even that takes an integer n as input and returns the next even number. That is, if n is even, the function should return the even number that is 2 greater than n. If n is odd, the function should return the even number that is 1 greater than n. The function should work for both positive and negative integers.
The test for this function should contain numbers that are positive, negative, even, and odd. Also include a test for the number 0.
Hint
You can test whether a number is even or odd using the modulus operator %. For example, n % 2 is 0 if n is even, and 1 if n is odd. Then, you can decide whether to add 1 or 2 to n to get the next even number.
Code 5.6: Cylinder Volume#
The volume of a cylinder is given by the formula \(V = A h\), where \(A\) is the area of the base of the cylinder, and \(h\) is the height of the cylinder. The area of the base is given by the formula \(A = \pi r^2\), where \(r\) is the radius of the base.
Write first the function disc_area that takes the radius of a disc as input and returns the area of the disc. Use math.pi as the value of \(\pi\), and remember to import the math module. Test your function.
Hint
You can use the following code to test your solution by comparing the expected output with the output of your function. This is only an indication (but not a guarantee!) that your solution is correct. For example, if you made a mistake and returned a string instead of a number, you would not notice this mistake by looking at the output.
print("Radius 1, expected disc area: 3.1415926535898, got:", disc_area(1))
print("Radius 2.8, expected disc area: 24.6300864041440, got:", disc_area(2.8))
print("Radius 14.5, expected disc area: 660.5198554173, got:", disc_area(14.5))
Hint
The following code provides better tests, as it compares the output of the function with the expected output. When comparing floating-point numbers, instead of using == it is better to check whether the two numbers are very close. This is because two correct solutions can be slightly different due to the way floating-point numbers are stored in the computer.
test1 = math.isclose(disc_area(1), 3.1415926535898)
test2 = math.isclose(disc_area(2.8), 24.6300864041440)
test3 = math.isclose(disc_area(14.5), 660.5198554173)
all_tests_passed = test1 and test2 and test3
print("All tests passed:", all_tests_passed)
if not all_tests_passed:
print("Individual test results:", test1, test2, test3)
Now, in the same file, write the function cylinder_volume that takes the radius and height of a cylinder as input and returns the volume of the cylinder. Can you write cylinder_volume in a way such that it uses (calls) disc_area?
Here, disc_area is a helper function for cylinder_volume. A helper function may be placed in the same file as the main function, or in a separate file that is imported similar to how you imported tests earlier today.
Problem Solving#
Problem 5.7: Parts to Ratio#
When mixing liquids, the mixing instructions are often given in parts. For example, instructions to mix elderflower syrup with water might say 1 + 4, which means that you should mix one part elderflower syrup with four parts water. Given such instructions, we are interested in knowing the ratio of the one part in relation to the total liquid. Again looking at the example 1+4, the obtained mixture has \(1 + 4 = 5\) parts in total, and the elderflower syrup is one part of this. Therefore, the ratio of elderflower syrup to the total liquid is \(\frac{1}{5} = 0.2\).
Write a function parts_to_ratio that takes two arguments, part and part_other, and returns the ratio of part in relation to the total liquid.
Hint
You can use the following code to test your solution by comparing the expected output with the output of your function.
import math
test1 = math.isclose(parts_to_ratio(1, 2), 1/3)
test2 = math.isclose(parts_to_ratio(3, 2), 3/5)
test3 = math.isclose(parts_to_ratio(5, 4), 5/9)
test4 = math.isclose(parts_to_ratio(1, 1), 1/2)
test5 = math.isclose(parts_to_ratio(7, 3), 7/10)
test6 = math.isclose(parts_to_ratio(2, 3), 2/5)
test7 = math.isclose(parts_to_ratio(4, 4), 4/8)
all_tests_passed = (test1 and test2 and test3 and test4 and test5 and test6
and test7)
print("All tests passed:", all_tests_passed)
Problem 5.8: Dilute Solution#
We want to dilute a solution by mixing it with a solvent. The mixing proportions are given in parts. The solution has a certain concentration, and after mixing it with the solvent, the concentration will be lowered. We want to compute the new concentration of the solution after it is mixed.
For example, consider having a solution that has a concentration of \(0.5\) g/L and mixing 2 parts of solution with 3 parts solvent. The resulting solution has \( 2 + 3 = 5 \) parts, of which 2 parts are the original solution. Therefore, the resulting concentration after dilution is \(\frac{2}{5}\cdot 0.5 = 0.2\) g/L.
Write a function dilute with arguments concentration, part_solution, and part_solvent that returns the concentration of the diluted solution.
Check
Check your solution by following the instructions below and comparing your result with ours.
Make a solution with 50 g/L of NaCl in water.
Dilute 2 parts of the solution with 3 parts of water.
Dilute it again by mixing 1 part of the previous solution with 4 parts of water.
Dilute it again by mixing 9 parts of the previous solution with 1 part of water.
The final concentration of the solution should be 3.6 g/L.
Problem 5.9: Profit Margin#
Profit margin measures the percentage of revenue that remains as profit after costs. The profit margin is calculated as
where \(r\) is the revenue and \(c\) is the cost.
Create a function called profit_margin that receives two parameters, cost and revenue, and returns the profit margin as a percentage. The following companies would like to know how much profit margin they have made in the last year. Use the function to calculate the profit margin for each company. We use 10**9 for a billion.
Company |
Cost ($) |
Revenue ($) |
Profit Margin (%) |
|---|---|---|---|
Lemonade stand inc. |
20 |
40 |
50 |
Floormart |
30 billion |
31 billion |
|
Ztartup |
200000 |
144000 |
|
Orange Inc. |
60 billion |
83 billion |
Problem 5.10: Beam Deflection#
The deflection of a beam is given by
where \(D\) is the deflection, \(M\) is the load, \(L\) is the length of the beam, \(\lambda\) is the modulus of elasticity, and \(I\) is the moment of inertia. The illustration below shows an unloaded and a loaded beam.
Write a function that calculates the deflection of a beam. The function requirements are:
beam_deflection.py
beam_deflection(length, load, modulus_of_elasticity, moment_of_inertia)
Calculate the deflection of a beam under a load.
Parameters:
|
|
The length of the beam (m). |
|
|
The load applied to the beam (N). |
|
|
The modulus of elasticity of the beam material (Pa). |
|
|
The moment of inertia of the beam’s cross-section (m). |
Returns:
|
The deflection of the beam (m). |
How to test this function? Consider first setting all parameters to 1 and calculate the expected result by hand. See if your function returns the same result.
Now try some more realistic values: a load of 500 N (approximately 51 kg applied) applied to a 2 m long steel beam with a rectangular 5 cm x 10 cm cross section. Steel has a modulus of elasticity of \(200 \times 10^9\) Pa, and the moment of inertia for this profile is \(I = \frac{bh^3}{12} = \frac{0.05 \cdot 0.1^3}{12} \approx 4.1667 \cdot 10^{-6}\ \mathrm{m}^4\).
Your function should give a deflection of approximately 1.6 mm.
Tip
To avoid spelling mistakes or errors in capitalization and punctuation, copy the text from this page and paste it into your code.
Problem 5.11: Wind Chill#
Wind chill is the lowering of body temperature due to the flow of cool air. The perceived temperature is the wind chill temperature \(T_{WC}\). The cooling effect depends on air temperature \(T\) and wind speed \(v\) with the formula:
where \(T\) is the temperature in degrees Celsius and \(v\) is the wind speed in km/h.
Write a function that takes as input the actual temperature (in degrees Celsius) and the wind speed (in km/h).
The function should return a string in the format
X degrees with Y km/h wind feels like Z degrees., where X is the actual temperature rounded to the nearest integer, Y is the wind speed rounded to the nearest integer, and Z is the perceived temperature rounded to the nearest integer.
The expected behavior of the function is shown below.
>>> wind_chill(-3.6, 25.6)
'-4 degrees with 26 km/h wind feels like -11 degrees.'
The function requirements are:
wind_chill.py
wind_chill(temperature, windspeed)
Calculate the wind chill index based on the temperature and wind speed.
Parameters:
|
|
The actual temperature in degrees Celsius. |
|
|
The wind speed in km/h. |
Returns:
|
A string describing the wind chill effect. |
Above, you can see how we specify the requirements for functions in this course. As explained in preparation, we show expected behavior in interactive mode, which you can recognize by the >>> prompt. Function requirements are shown in a box with the name of the file in the frame above the box.
To test your wind_chill function, we have provided test code in the file test_wind_chill.py. The test code imports your function and checks whether it works as expected, just as you practiced in the Buddy Exercise in Code 5.3. Download the file and place it in the same folder as your function file; otherwise, the import will not work.
Run the test file to check your function. It runs four tests and reports the expected output and your function’s output when a test fails.
Problem 5.12: Bacterial Growth#
We grow bacteria in a closed container that can sustain a certain number of bacteria. To investigate bacterial growth, we use the model
where \(\Delta N\) is the change in the number of bacteria from one hour to another, \(r\) is the hourly growth rate, \(N\) is the number of bacteria, and \(K\) is the maximum number of bacteria that can be in the container. The expression in the parentheses is the fraction of the container that is empty. So if no space is empty and \(N = K\) the number of bacteria will not increase further.
Starting from an initial population, we want to know how many hours it will take for the bacteria to fill more than 90% of the container.
Consider \(N=100\), \(r=0.1\), and \(K=1000\). After one hour, the population will be 109, then approximately 118.7, 129.2, 140.4, and so on. The population will reach 90% of the maximum population after 44 hours.
Create a file called bacterial_growth.py. In this file create a function with the following specifications:
bacterial_growth.py
bacterial_growth(initial, growth_rate, max_bact)
Simulates bacterial growth and returns the time taken to reach 90% of the maximum population.
Parameters:
|
|
The initial number of bacteria. |
|
|
The growth rate of the bacteria. |
|
|
The maximum population of the bacteria. |
Returns:
|
The number of hours for the bacteria to reach 90% of the maximum population. Returns -1 if the population does not reach 90% within one week. |
One expected output is shown below.
>>> bacterial_growth(100.0, 0.1, 1000.0)
44
To test your function, we have provided test code in the file test_bacterial_growth.py. This file contains only one test, so you may wonder whether it is worth using. However, it can catch simple mistakes such as misspelling the filename or the function name, so there is still value in using it.
Problem 5.13: Which Fibonacci?#
The Fibonacci sequence is a series of numbers where each number is the sum of the two preceding ones. The sequence starts as follows:
Create a function which_fibonacci that takes an integer as input, and returns which position this integer has in the list of fibonacci numbers. If the number is not in the list, the function should return -1.
To avoid ambiguities, you can assume the input is 2 or greater.
For example, the number 5 is the 6th fibonacci number, so which_fibonacci(5) should return 6.
Here are some additional examples:
>>> which_fibonacci(5)
6
>>> which_fibonacci(14)
-1
>>> which_fibonacci(14930352)
37
The function specifications are:
which_fibonacci.py
which_fibonacci(n)
Determines which Fibonacci number the input is.
Parameters:
|
|
The number we wish to test. |
Returns:
|
The position in the list of Fibonacci numbers. If it is not in the list, return |
Solutions to Demo Tasks
Solution to Demo 5.1: Fall Duration
def fall_duration(s):
g = 9.81
t = (2 * s / g) ** 0.5
return t
Solution to Demo 5.2: Customized Greeting
def customized_greeting(hours, minutes):
if (hours < 4) or ((hours == 4) and (minutes < 30)):
greeting = 'Good night!'
elif (hours < 12):
greeting = 'Good morning!'
elif (hours < 17) or ((hours == 17) and (minutes < 30)):
greeting = 'Good afternoon!'
elif hours < 23:
greeting = 'Good evening!'
else:
greeting = 'Good night!'
return greeting