## Exercises

**2.1.1** Compose a function `max3()` that takes three `int` or `float` arguments and returns the largest one.

**2.1.2** Compose a function `odd()` that takes three `bool` arguments and returns `True` if an odd number of arguments are `True`, and `False` otherwise.

**2.1.3** Compose a function `majority()` that takes three `bool` arguments and returns `True` if at least two of the arguments are `True`, and `False` otherwise. Do not use an `if` statement.

**2.1.4** Compose a function `areTriangular()` that takes three numbers as arguments and returns `True` if they could be lengths of the sides of a triangle (none of them is greater than or equal to the sum of the other two), and `False` otherwise.

**2.1.5** Compose a function `sigmoid()` that takes a `float` argument `x` and returns the `float` obtained from the formula 1 / (1+*e*^{−x}).

**2.1.6** Compose a function `lg()` that takes an integer `n` as an argument and returns the base-2 logarithm of `n`. You may use Python’s `math` module.

**2.1.7** Compose a function `lg()` that takes an integer `n` as an argument and returns the largest integer not larger than the base-2 logarithm of `n`. Do *not* use the `math` module.

**2.1.8** Compose a function `signum()` that takes a `float` argument `n` and returns `-1` if `n` is less than `0`, `0` if `n` is equal to `0`, and `+1` if `n` is greater than `0`.

**2.1.9** Consider this function `duplicate()`:

def duplicate(s): t = s + s

What does the following code fragment write?

s = 'Hello' s = duplicate(s) t = 'Bye' t = duplicate(duplicate(duplicate(t))) stdio.writeln(s + t)

**2.1.10** Consider this function `cube()`:

def cube(i): i = i * i * i

How many times is the following `while` loop iterated?

i = 0 while i < 1000: cube(i) i += 1

*Solution:* Just 1,000 times. A call to `cube()` has no effect on the client code. It changes the parameter variable `i`, but that change has no effect on the variable `i` in the `while` loop, which is a different variable. If you replace the call to `cube(i)` with the statement` i = i * i * i` (maybe that was what you were thinking), then the loop is iterated five times, with `i` taking on the values `0`, `1`, `2`, `9`, and `730` at the beginning of the five iterations.

**2.1.11** What does the following code fragment write?

for i in range(5): stdio.write(i) for j in range(5): stdio.write(i)

*Solution:* `0123444444`. Note that the second call to `stdio.write()` uses `i`, not `j`. Unlike analogous loops in many other programming languages, when the first `for` loop terminates, the variable `i` is `4` and it remains in scope.

**2.1.12** The following *checksum* formula is widely used by banks and credit card companies to validate legal account numbers:

- d
_{0}+*f*(*d*_{1}) +*d*_{2}+*f*(*d*_{3}) +*d*_{4}+*f*(*d*_{5}) + . . . = 0 (mod 10)

The *d** _{i}* are the decimal digits of the account number and

*f*(

*d*) is the sum of the decimal digits of 2

*d*(for example,

*f*(7) = 5 because 2 × 7 = 14 and 1 + 4 = 5). For example 17327 is valid because 1 + 5 + 3 + 4 + 7 = 20, which is a multiple of 10. Implement the function

*f*and compose a program to take a 10-digit integer as a command-line argument and write a valid 11-digit number with the given integer as its first 10 digits and the checksum as the last digit.

**2.1.13** Given two stars with angles of declination and right ascension (*d*_{1}, *a*_{1}) and (*d*_{2}, *a*_{2}), respectively, the angle they subtend is given by the formula

- 2 arcsin((sin
^{2}(*d*/2) + cos (*d*_{1})cos(*d*_{2})sin^{2}(*a*/2))^{1/2}),

where *a*_{1} and *a*_{2} are angles between −180 and 180 degrees, *d*_{1} and *d*_{2} are angles between −90 and 90 degrees, *a* = *a*_{2} − *a*_{1}, and *d* = *d*_{2} −*d*_{1}. Compose a program to take the declination and right ascension of two stars as command-line arguments and write the angle they subtend. *Hint* : Be careful about converting from degrees to radians.

**2.1.14** Compose a `readBool2D()` function that reads a two-dimensional matrix of 0 and 1 values (with dimensions) into an array of booleans.

*Solution*: The body of the function is virtually the same as for the corresponding function given in the table in the text for two-dimensional arrays of floats:

def readBool2D(): m = stdio.readInt() n = stdio.readInt() a = stdarray.create2D(m, n, False) for i in range(m): for j in range(n): a[i][j] = stdio.readBool() return a

**2.1.15** Compose a function that takes an array `a[]` of strictly positive floats as its argument and rescales the array so that each element is between 0 and 1 (by subtracting the minimum value from each element and then dividing each element by the difference between the minimum and maximum values). Use the built-in `max()` and `min()` functions.

**2.1.16** Compose a function `histogram()` that takes an array `a[]` of integers and an integer `m` as arguments and returns an array of length `m` whose `i`th element is the number of times the integer `i` appears in the argument array. Assume that the values in `a[]` are all between `0` and `m-1`, so that the sum of the values in the returned array should be equal to `len(a)`.

**2.1.17** Assemble code fragments in this section and in SECTION 1.4 to develop a program that takes an integer `n` from the command line and writes `n` five-card hands, separated by blank lines, drawn from a randomly shuffled card deck, one card per line using card names like `Ace of Clubs`.

**2.1.18** Compose a function m`ultiply()` that takes two square matrices of the same dimension as arguments and returns their product (another square matrix of that same dimension). *Extra credit *: Make your program work whenever the number of columns in the first matrix is equal to the number of rows in the second matrix.

**2.1.19** Compose a function `any()` that takes an array of booleans as an argument and returns `True` if *any* of the elements in the array is `True`, and `False` otherwise. Compose a function `all()` that takes an array of booleans as an argument and returns `True` if *all* of the elements in the array are `True`, and `False` otherwise. Note that `all() `and `any()` are built-in Python functions; the goal of this exercise is to understand them better by creating your own versions.

**2.1.20** Develop a version of `getCoupon()` that better models the situation when one of the *n* coupons is rare: choose one value at random, return that value with probability 1/(1000*n*), and return all other values with equal probability. *Extra credit*: How does this change affect the average value of the coupon collector function?

**2.1.21** Modify `playthattune.py` to add harmonics two octaves away from each note, with half the weight of the one-octave harmonics.