""" This module lets you practice the ACCUMULATOR pattern in several classic forms: SUMMING: total = total + number COUNTING: count = count + 1 AVERAGING: summing and counting combined and FACTORIAL: x = x * k Subsequent modules let you practice the ACCUMULATOR pattern in its "in graphics" form: IN GRAPHICS: x = x + pixels Authors: David Mutchler, Vibha Alangar, Dave Fisher, Matt Boutell, Mark Hays, Mohammed Noureddine, Sana Ebrahimi, Sriram Mohan, their colleagues and PUT_YOUR_NAME_HERE. """ # TODO: 1. PUT YOUR NAME IN THE ABOVE LINE. import math import builtins # Never necessary, but here for pedagogical reasons # ----------------------------------------------------------------------------- # Students: As you work each of these problems, ask yourself: # 1. Do I need a loop? # If so, HOW MANY LOOPS? # # 2. Where I need a loop, what needs to happen: # -- BEFORE the loop? # -- IN the loop? # -- AFTER the loop? # ----------------------------------------------------------------------------- ############################################################################## # TODO: 2. Read the following, then change its _TODO_ to DONE. # Throughout these exercises, you must use RANGE statements. # At this point of the course, you are restricted to the SINGLE-ARGUMENT # form of RANGE statements, like this: # range(blah): # There is a MULTIPLE-ARGUMENT form of RANGE statements (e.g. range(a, b)) # but you are NOT permitted to use the MULTIPLE-ARGUMENT form yet, for # pedagogical reasons. Change the above _TODO_ to DONE after reading this. ############################################################################### def main(): """ Calls the TEST functions in this module. """ print("-----------------------------------------------") print("Un-comment each of the following TEST functions") print("as you implement the functions that they test.") print("-----------------------------------------------") # run_test_sum_from() # run_test_factorial() # run_test_count_cosines_from() # run_test_sum_unit_fractions_from() # ----------------------------------------------------------------------------- # Students: READ the run_test_sum_from function that follows this comment. # ----------------------------------------------------------------------------- def run_test_sum_from(): """ Tests the sum_from function. """ print() print("--------------------------------------------------") print("Testing the sum_from function:") print("--------------------------------------------------") # ------------------------------------------------------------------------- # These first two tests use an ORACLE for testing, # that is, a way to get the answer by using some other approach # that is known to work correctly. # The oracle here is the builtins.sum function. # ------------------------------------------------------------------------- # Test 1: answer_from_oracle = builtins.sum(range(6, 10)) answer_from_my_code = sum_from(6, 9) print("Test 1 expected (from oracle):", answer_from_oracle) print(" actual (from my code): ", answer_from_my_code) # Test 2: answer_from_oracle = builtins.sum(range(100, 10001)) answer_from_my_code = sum_from(100, 10000) print("Test 2 expected (from oracle):", answer_from_oracle) print(" actual (from my code): ", answer_from_my_code) # ------------------------------------------------------------------------- # The next test uses a KNOWN answer (usually computed by hand). # (Everyone "knows" that the sum from 0 to 3 is 0+1+2+3, i.e. 6.) # ------------------------------------------------------------------------- # Test 3: answer_from_by_hand = 6 answer_from_my_code = sum_from(0, 3) print("Test 3 expected (from by-hand):", answer_from_by_hand) print(" actual (from my code): ", answer_from_my_code) # ------------------------------------------------------------------------- # The next test uses a FORMULA answer (which is one kind of ORACLE answer) # that uses the formula: # m + (m+1) + (m+2) + ... + n = (m + n) * (n - m + 1) / 2 # ------------------------------------------------------------------------- # Test 4: answer_from_formula = (53 + 4999) * (4999 - 53 + 1) // 2 answer_from_my_code = sum_from(53, 4999) print("Test 4 expected (from formula):", answer_from_formula) print(" actual (from my code): ", answer_from_my_code) # ----------------------------------------------------------------------------- # TODO: 3. # When you have READ the above run_test_sum_from function, # asking questions as needed, and you feel that you (mostly, at least) # understand it, and you feel that you understand from the example: # -- what an ORACLE answer is # -- what a KNOWN (typically, BY-HAND) answer is # -- what a FORMULA answer is # -- how the above are used in testing # THEN: # CHANGE THE _TODO_ at the beginning of this comment to DONE. # here is no code to be written for this _TODO_ (just reading). # ----------------------------------------------------------------------------- def sum_from(m, n): """ What comes in: The arguments are two integers m and n, with m <= n. What goes out: Returns the sum of the integers from m to n, inclusive. Side effects: None. Example: sum_from(6, 9) returns 6 + 7 + 8 + 9, that is, 30. Type hints: :type m: int :type n: int :rtype: int """ # ------------------------------------------------------------------------- # TODO: 4. Implement and test this function. # Tests have been written for you (above). # _ # IMPORTANT: Your solution MUST # use an explicit for ... in range(...): statement # _ # IMPORTANT: As in previous problems in this session, # you must NOT use the 2 or 3-parameter versions # of the RANGE expression, if you happen to know them. # ------------------------------------------------------------------------- def run_test_factorial(): """ Tests the factorial function. """ # ------------------------------------------------------------------------- # TODO: 5. Implement this TEST function. # It TESTS the factorial function defined below. # Include at least ** 5 ** tests (we wrote two for you). # ######################################################################## # IMPORTANT: At least 2 of your tests MUST use the # math.factorial # function as an ORACLE for testing. See examples above. # ######################################################################## # ------------------------------------------------------------------------- print() print("--------------------------------------------------") print("Testing the factorial function:") print("--------------------------------------------------") # Test 1: answer_from_oracle = math.factorial(0) answer_from_my_code = factorial(0) print("Test 1 expected (from oracle):", answer_from_oracle) print(" actual (from my code): ", answer_from_my_code) # Test 2: answer_from_oracle = math.factorial(21) answer_from_my_code = factorial(21) print("Test 2 expected (from oracle):", answer_from_oracle) print(" actual (from my code): ", answer_from_my_code) # ------------------------------------------------------------------------- # TODO: 5 (continued). # Below this comment, add 3 more test cases, at least two of which # ** uses math.factorial as an ORACLE for testing. ** # ------------------------------------------------------------------------- def factorial(n): """ What comes in: The sole argument is a non-negative integer n. What goes out: Returns n!, that is, n x (n-1) x (n-2) x ... x 1. Side effects: None. Examples: factorial(5) returns 5 x 4 x 3 x 2 x 1, that is, 120. factorial(0) returns 1 (by definition). Type hints: :type n: int :rtype: int """ # ------------------------------------------------------------------------- # TODO: 6. Implement and test this function. # Note that you should write its TEST function first (above). # _ # IMPORTANT: Your solution MUST # use an explicit for ... in range(...): statement. # ------------------------------------------------------------------------- def run_test_count_cosines_from(): """ Tests the count_cosines_from function. """ # ------------------------------------------------------------------------- # TODO: 7. Implement this TEST function. # It TESTS the count_cosines_from function defined below. # Include at least ** 6 ** tests (we wrote one for you). # ** Yes, 6 (six) tests. ** # ** Counting problems are harder to test than summing. ** # ___ # To implement this TEST function, use the same 4 steps as before: # ___ # Step 1: Read the doc-string of count_cosines_from below. # Understand what that function SHOULD return. # ___ # Step 2: Pick a test case: numbers that you could send as # actual arguments to the count_cosines_from function. # ___ # Step 3: Figure out (by hand, or by using an oracle: a test case # that your instructor provided in the doc-string, or a # known formula or an alternative implementation that you trust) # the CORRECT (EXPECTED) answer for your test case. # ___ # Step 4: Write code that prints both the EXPECTED answer # and the ACTUAL answer returned when you call the function. # Follow the same form as in the test case we provided below. # ------------------------------------------------------------------------- print() print("--------------------------------------------------") print("Testing the count_cosines_from function:") print("--------------------------------------------------") # Test 1: expected = 2 answer = count_cosines_from(3, 9, 0.29) print("Test 1 expected:", expected) print(" actual: ", answer) # ------------------------------------------------------------------------- # TODO: 7 (continued). # Below this comment, add 5 more test cases of your own choosing. # ------------------------------------------------------------------------- def count_cosines_from(m, n, x): """ What comes in: The three arguments are two non-negative integers m and n, with m <= n, and a number x. What goes out: Returns the number of integers from m to n, inclusive, whose cosine is greater than x. Side effects: None. Examples: Since: cosine(3) is about -0.99 cosine(4) is about -0.65 cosine(5) is about 0.28 cosine(6) is about 0.96 cosine(7) is about 0.75 cosine(8) is about -0.15 cosine(9) is about -0.91 -- count_cosines_from(3, 9, 0.29) returns 2 -- count_cosines_from(3, 9, 0.27) returns 3 -- count_cosines_from(4, 8, -0.5) returns 4 Type hints: :type m: int :type n: int :type x: int | float :rtype: int """ # ------------------------------------------------------------------------- # TODO: 8. Implement and test this function. # Note that you should write its TEST function first (above). # _ # IMPORTANT: As in previous problems in this session, # you must NOT use the 2 or 3-parameter versions # of the RANGE expression, if you happen to know them. # ------------------------------------------------------------------------- def run_test_sum_unit_fractions_from(): """ Tests the sum_unit_fractions_from function. """ # ------------------------------------------------------------------------- # TODO: 9. Implement this TEST function. # It TESTS the sum_unit_fractions_from function defined below. # Include at least ** 3 ** tests (we wrote one for you). # Use the same 4-step process as for previous TEST functions. # ------------------------------------------------------------------------- print() print("--------------------------------------------------") print("Testing the sum_unit_fractions_from function:") print("--------------------------------------------------") # Test 1: expected = 0.545635 # This is APPROXIMATELY the correct answer. answer = sum_unit_fractions_from(6, 9) print("Test 1 expected:", expected, "(approximately)") print(" actual: ", answer) # ------------------------------------------------------------------------- # TODO: 9 (continued). # Below this comment, add 2 more test cases of your own choosing. # ------------------------------------------------------------------------- def sum_unit_fractions_from(m, n): """ What comes in: Two positive integers m and n with m <= n. What goes out: Returns the sum: 1/m + 1/(m+1) + 1/(m+2) + ... + 1/n. Side effects: None. Examples: -- sum_unit_fractions_from(6, 9) returns 1/6 + 1/7 + 1/8 + 1/9 which is about 0.545635 -- sum_unit_fractions_from(10, 9000) returns about 6.853 Type hints: :type m: int :type n: int :rtype: float """ # ------------------------------------------------------------------------- # TODO: 10. Implement and test this function. # Note that you should write its TEST function first (above). # _ # IMPORTANT: As in previous problems in this session, # you must NOT use the 2 or 3-parameter versions # of the RANGE expression, if you happen to know them. # ------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # Calls main to start the ball rolling. # ----------------------------------------------------------------------------- main()