Engineering Computing

Write a program in a single script that meets the following requirements:

  1. It imports the standard library random module.
  2. It defines a function rand_sub() that defines a list of grammatical subjects (e.g., Jim, I, you, skeletons, a tiger, etc.) and returns a random subject; consider using random.choice() function.
  3. It defines a function rand_verb() that defines a list of verbs in past tense (e.g., opened, smashed, ate, became, etc.) and returns a random verb.
  4. It defines a function rand_obj() that defines a list of grammatical objects (e.g., the closet, her, crumbs, organs) and returns a random object.
  5. It defines a function rand_sen() that returns a random subject-verb-object sentence as a string beginning with a capital letter and ending with a period.
  6. It defines a function rand_par() that returns a random paragraph as a string composed of \(3\) to \(5\) sentences (the number of sentences should be random—consider using the random.randint(a, b) function that generates an int between a and b, inclusively). Sentences should be separated by a space " " character.
  7. It calls rand_par() three times and prints the results.

The following program meets the requirements:

import random

def rand_sub():
    """Returns a random grammatical subject"""
    subjects = [
        "I", "you", "Jim", "Helen", "Socrates", "skeletons",
        "a stick", "the undead", "Bilbo", "the youth",
        "all the children", "a unicorn", "several snakes",
        "Taylor Swift", "Hamlet", "an unkindness of ravens",
        "huge rats", "Kant", "Beauvoir", "they", 
        "the rest of them", "he", "she", "Pam", "a bunch",
    ]
    return random.choice(subjects)

def rand_verb():
    """Returns a random verb"""
    verbs = [
        "opened", "smashed", "ate", "became", "climbed",
        "chose", "questioned", "grew", "squeezed", "read",
        "sought", "lifted", "outpaced", "surprised",
        "sauteed", "dissected", "displayed", "coughed up",
        "stole", "got rid of", "dispatched", "clung to",
    ]
    return random.choice(verbs)

def rand_obj():
    """Returns a random grammatical object"""
    objects = [
        "the closet", "her", "crumbs", "organs", "cheese",
        "the best ones", "a hippo", "the lot of them",
        "those assembled", "him", "platters", "the whiskey",
        "jumbo shrimp", "the strangest one", "the wind",
        "spoons galore", "a book", "a mirror", "a blessed spirit",
        "a path most perilous", "most", "a hungry caterpillar",
    ]
    return random.choice(objects)

def rand_sen():
    """Returns a random subject-verb-object sentence"""
    s = rand_sub()
    v = rand_verb()
    o = rand_obj()
    sentence = " ".join([s.capitalize(), v, o]) + "."
    return sentence

def rand_par():
    """Returns a paragraph of random sentences"""
    n_sentences = random.randint(3, 5)
    paragraph = ""
    for i in range(0, n_sentences):
        paragraph += " " + rand_sen()
    return paragraph

for i in range(0,3):
    print(rand_par())

This program prints the following to the console:

 Helen squeezed the closet. He questioned spoons galore. The undead stole the strangest one.
 She outpaced him. Several snakes coughed up a path most perilous. Beauvoir sought the best ones.
 All the children clung to most. Huge rats opened a blessed spirit. Kant opened the lot of them. Pam ate jumbo shrimp.

Rewrite the program from problem 2.1 such that it meets the following requirements:

  1. It defines the functions in a separate module with the file name rand_speech_parts.py.
  2. Instead of defining the lists of subjects, verbs, and objects inside the functions, it assigns a variable to each list in the module’s global namespace and accesses them from within the functions. Why is this preferable?
  3. It imports the module into the main script.
  4. It print three random paragraphs, as before.

The following program meets the requirements. First, the module rand_speech_parts.py contains the following:

import random

subjects = [
    "I", "you", "Jim", "Helen", "Socrates", "skeletons",
    "a stick", "the undead", "Bilbo", "the youth",
    "all the children", "a unicorn", "several snakes",
    "Taylor Swift", "Hamlet", "an unkindness of ravens",
    "huge rats", "Kant", "Beauvoir", "they", 
    "the rest of them", "he", "she", "Pam", "a bunch",
]
verbs = [
    "opened", "smashed", "ate", "became", "climbed",
    "chose", "questioned", "grew", "squeezed", "read",
    "sought", "lifted", "outpaced", "surprised",
    "sauteed", "dissected", "displayed", "coughed up",
    "stole", "got rid of", "dispatched", "clung to",
]
objects = [
    "the closet", "her", "crumbs", "organs", "cheese",
    "the best ones", "a hippo", "the lot of them",
    "those assembled", "him", "platters", "the whiskey",
    "jumbo shrimp", "the strangest one", "the wind",
    "spoons galore", "a book", "a mirror", "a blessed spirit",
    "a path most perilous", "most", "a hungry caterpillar",
]

def rand_sub():
    """Returns a random grammatical subject"""
    return random.choice(subjects)

def rand_verb():
    """Returns a random verb"""
    return random.choice(verbs)

def rand_obj():
    """Returns a random grammatical object"""
    return random.choice(objects)

def rand_sen():
    """Returns a random subject-verb-object sentence"""
    s = rand_sub()
    v = rand_verb()
    o = rand_obj()
    sentence = " ".join([s.capitalize(), v, o]) + "."
    return sentence

def rand_par():
    """Returns a paragraph of random sentences"""
    n_sentences = random.randint(3, 5)
    paragraph = ""
    for i in range(0, n_sentences):
        paragraph += " " + rand_sen()
    return paragraph

It is better to move the lists of words outside the functions’ local namespaces and into the module’s global namespace because the functions’ namespaces those are created and then destroyed at each function call. It is more efficient to define the lists once and access them within the functions (the scope of each list variable being inclusive of the function blocks).

The main script contains the following:

import rand_speech_parts

for i in range(0,3):
    print(rand_speech_parts.rand_par())

Running the main script prints the following to the console:

 Jim ate the closet. Kant grew the lot of them. All the children got rid of her. The undead got rid of a path most perilous. Socrates displayed the closet.
 Beauvoir grew a blessed spirit. A stick climbed the closet. Socrates got rid of a hippo. An unkindness of ravens grew spoons galore. A stick grew cheese.
 Pam read her. Socrates ate the wind. The undead smashed a hippo.

Write a program in a single script that meets the following requirements:

  1. It imports the standard library random module.

  2. It defines a function rand_step(x, d, ymax, wrap=True) that returns a float that is the sum of x and a uniformly distributed random float between -d and d. Consider using the random.uniform(a, b) function that returns a random float between a and b. If wrap is True, it maps a stepped value y > ymax to y - ymax and a stepped value y < 0 to ymax + y. If wrap is False, it maps a stepped value y > ymax to ymax and a stepped value y < 0 to 0.

  3. It defines a function rand_steps(x0, d, ymax, n, wrap=True) that returns a list of n floats that are sequentially stepped from x0. It passes wrap to its call to rand_step().

  4. It defines a function print_slider(k, x) that prints k characters, all of which are - except that which has index closest to x, for which it prints |. For instance, print_slider(17, 6.8) should print

    -------|---------

    Consider using the built-in round() function.

  5. It defines a function rand_sliders(n, k, x0=None, d=3, wrap=True) that prints n random sliders of k characters and max step d starting at the index closest to x0, if provided, and otherwise at the index closest k/2.

  6. It prints \(25\) random wrapped sliders of \(44\) characters with the default step range and starting point \(2\).

  7. It prints \(20\) random nonwrapped sliders of \(44\) characters with the step range \(5\) and starting point \(42\).

The following program meets the requirements:

# %% [markdown]
## Packages
# %%
import random

# %% [markdown]
## Functions
# %%
def rand_step(x, d, ymax, wrap=True):
    """Returns the sum of x and a random float between -d and d"""
    step = random.uniform(-d, d)
    y = x + step
    if wrap:
        if y > ymax:
            y = y - ymax
        elif y < 0:
            y = ymax + y
    else:
        if y > ymax:
            y = ymax
        elif y < 0:
            y = 0
    return y


def rand_steps(x0, d, ymax, n, wrap=True):
    """Returns a list of n floats sequentially stepped from x0"""
    values = [x0]
    for i in range(0, n):
        values.append(rand_step(values[-1], d, ymax, wrap=wrap))
    return values


def print_slider(k, x):
    """Prints k '-' characters except for that with index
    closest to x, which prints |
    """
    x_rounded = round(x)
    if x_rounded < 0:
        x_rounded = 0  # Coerce to 0
    elif x_rounded > k:
        x_rounded = k - 1  # Coerce to max index
    for i in range(0, k):
        if i == x_rounded:
            print("|", end="")
        else:
            print("-", end="")
    print("")  # Line break applied


def rand_sliders(n, k, x0=None, d=3, wrap=True):
    """Prints n random sliders with k characters"""
    if not x0:
        x0 = k / 2  # Start in the middle
    values = rand_steps(
        x0,  # Initial value
        d,  # Max step size
        ymax=k - 1,  # Subtract 1 because 0-indexed
        n=n,  # One value per slider
        wrap=wrap,  # Pass wrap
    )
    for x in values:
        print_slider(k, x)


# %% [markdown]
## Call Functions and Print
# %%
print("rand_sliders(25, 44, x0=2, wrap=True):")
rand_sliders(25, 44, x0=2, wrap=True)
print("rand_sliders(20, 44, x0=42, d=5, wrap=False):")
rand_sliders(20, 44, x0=42, d=5, wrap=False)

# %% tags=["active-py"]
import sys

sys.path.append("../")
import engcom.engcom as engcom

pub = engcom.Publication(title="Problem YE", author="Rico Picone")
pub.write(to="pdf")

This program prints the following to the console:

rand_sliders(25, 44, x0=2, wrap=True):
--|-----------------------------------------
----|---------------------------------------
--|-----------------------------------------
----|---------------------------------------
-----|--------------------------------------
------|-------------------------------------
------|-------------------------------------
----|---------------------------------------
-----|--------------------------------------
-----|--------------------------------------
-------|------------------------------------
-----|--------------------------------------
--|-----------------------------------------
-----|--------------------------------------
-------|------------------------------------
--------|-----------------------------------
---------|----------------------------------
----------|---------------------------------
-------------|------------------------------
------------|-------------------------------
------------|-------------------------------
-------------|------------------------------
------------|-------------------------------
---------|----------------------------------
--------|-----------------------------------
-------|------------------------------------
rand_sliders(20, 44, x0=42, d=5, wrap=False):
------------------------------------------|-
--------------------------------------|-----
-------------------------------------------|
-------------------------------------------|
----------------------------------------|---
-------------------------------------------|
-----------------------------------------|--
--------------------------------------|-----
------------------------------------|-------
---------------------------------|----------
----------------------------------|---------
------------------------------|-------------
--------------------------|-----------------
---------------------|----------------------
-----------------------|--------------------
----------------------|---------------------
-----------------------|--------------------
---------------------|----------------------
-------------------------|------------------
-------------------------|------------------
------------------------|-------------------

Rewrite the program from problem 2.3 such that it meets the following requirements:

  1. It defines the functions in a separate module with the file name rand_sliding.py.
  2. It imports the module into the main script.
  3. It prints \(25\) random wrapped sliders of \(44\) characters with the default step range and starting point \(42\).
  4. It prints \(20\) random nonwrapped sliders of \(44\) characters with the step range \(5\) and starting point \(2\).

The following program meets the requirements. First, the module rand_sliding.py contains the following:

import random

def rand_step(x, d, ymax, wrap=True):
    """Returns the sum of x and a random float between -d and d"""
    step = random.uniform(-d, d)
    y = x + step
    if wrap:
        if y > ymax:
            y = y - ymax
        elif y < 0:
            y = ymax + y
    else:
        if y > ymax:
            y = ymax
        elif y < 0:
            y = 0
    return y

def rand_steps(x0, d, ymax, n, wrap=True):
    """Returns a list of n floats sequentially stepped from x0"""
    values = [x0]
    for i in range(0,n):
        values.append(
            rand_step(values[-1], d, ymax, wrap=wrap)
        )
    return values

def print_slider(k, x):
    """Prints k '-' characters except for that with index 
        closest to x, which prints |
    """
    x_rounded = round(x)
    if x_rounded < 0:
        x_rounded = 0        # Coerce to 0
    elif x_rounded > k:
        x_rounded = k - 1    # Coerce to max index
    for i in range(0,k):
        if i == x_rounded:
            print("|", end="")
        else:
            print("-", end="")
    print("") # Line break applied

def rand_sliders(n, k, x0=None, d=3, wrap=True):
    """Prints n random sliders with k characters"""
    if not x0:
        x0 = k/2    # Start in the middle
    values = rand_steps(
        x0,         # Initial value
        d,          # Max step size
        ymax=k-1,   # Subtract 1 because 0-indexed
        n=n,        # One value per slider
        wrap=wrap   # Pass wrap
    )
    for x in values:
        print_slider(k, x)

The main script contains the following:

import rand_sliding

print("rand_sliding.rand_sliders(25, 44, x0=42, wrap=True):")
rand_sliding.rand_sliders(25, 44, x0=42, wrap=True)
print("rand_sliding.rand_sliders(20, 44, x0=2, d=5, wrap=False):")
rand_sliding.rand_sliders(20, 44, x0=2, d=5, wrap=False)

Running the main script prints the following to the console:

rand_sliding.rand_sliders(25, 44, x0=42, wrap=True):
------------------------------------------|-
----------------------------------------|---
-----------------------------------------|--
|-------------------------------------------
--|-----------------------------------------
------------------------------------------|-
----------------------------------------|---
---------------------------------------|----
-------------------------------------|------
-----------------------------------|--------
-------------------------------------|------
------------------------------------|-------
---------------------------------|----------
--------------------------------|-----------
----------------------------------|---------
-------------------------------|------------
---------------------------------|----------
-----------------------------------|--------
------------------------------------|-------
------------------------------------|-------
----------------------------------|---------
---------------------------------|----------
----------------------------------|---------
-------------------------------|------------
------------------------------|-------------
--------------------------------|-----------
rand_sliding.rand_sliders(20, 44, x0=2, d=5, wrap=False):
--|-----------------------------------------
|-------------------------------------------
-----|--------------------------------------
-------|------------------------------------
--------|-----------------------------------
----|---------------------------------------
-------|------------------------------------
---------|----------------------------------
------------|-------------------------------
---------------|----------------------------
-----------------|--------------------------
---------------|----------------------------
------------|-------------------------------
----------|---------------------------------
------|-------------------------------------
-------|------------------------------------
---|----------------------------------------
--|-----------------------------------------
------|-------------------------------------
-----|--------------------------------------
----------|---------------------------------

Begin with the Screwdriver, Screw, and SetScrew class definitions of section 2.5. Add the following features:

  • Improve the Screwdriver.drive() method to check that its head matches the screw head and raise a TypeError exception if they do not
  • Improve the Screw class by adding instance attributes pitch that stores the thread pitch in mm and depth that stores the depth of the screw in its hole
  • Improve the Screw.turn() method to mutate the depth based on the angle it is turned, its handing, and its thread pitch1
  • Create a subclass MetricScrew from the base class Screw with the additional class data attribute kind = "Metric"

Test the new features of the Screwdriver, Screw, and MetricScrew classes with the following steps:

  1. Create an instance ms1 of MetricScrew with right-handedness, a flat head, initial angle \(0\) rad, and thread pitch \(2\) mm (corresponding to an M14 metric screw)
  2. Create an instance sd1 of Screwdriver with a flat head
  3. Turn the ms1 screw \(5\) complete clockwise revolutions with the sd1 screwdriver and print the resulting angle and depth of ms1
  4. Turn the ms1 screw \(3\) complete counterclockwise revolutions with the sd1 screwdriver and print the resulting angle and depth of ms1
  5. Create an instance ms2 of MetricScrew that is the same as ms1, but with left-handedness
  6. Turn the ms2 screw \(4\) complete counterclockwise revolutions with the sd1 screwdriver and print the resulting angle and depth of ms2
  7. Turn the ms2 screw \(2\) complete clockwise revolutions with the sd1 screwdriver and print the resulting angle and depth of ms2
  8. Create an instance sd2 of Screwdriver with a hex head and try to turn the sd1 screw and catch and print the exception

Load the NumPy package:

import numpy as np

Define Classes

The following Screwdriver class meets the requirements:

class Screwdriver:
    """Represents a screwdriver tool"""
    operates_on = "Screw"  # Class data attributes
    operated_by = "Hand"
    
    def __init__(self, head, length):
        self.head = head  # Instance data attributes
        self.length = length
    
    def drive(self, screw, angle):  # Method definition
        """Returns a screw object turned by the given angle"""
        if screw.head != self.head:
            raise TypeError(f"{self.head} screwdriver "
                f"can't turn a {screw.head} screw.")
        screw.turn(angle)
        return screw

The following Screw class meets the requirements:

class Screw:
    """Represents a screw fastener"""
    def __init__(self, head, pitch, depth=0, angle=0, handed="Right"):
        self.head = head
        self.pitch = pitch
        self.depth = depth
        self.angle = angle
        self.handed = handed
        
    def turn(self, angle):
        """Mutates angle and depth for a turn of angle rad"""
        if self.handed == "Right":
            handed_sign = 1
        else:
            handed_sign = -1
        self.angle += angle
        self.depth += handed_sign * self.pitch * angle / (2*np.pi)

The following MetricScrew class meets the requirements:

class MetricScrew(Screw):
    """Represents a metric screw fastener"""
    kind = "Metric"
    # No constructor necessary because we aren't 
    # changing instance attributes

Test the New Features

Create a MetricScrew instance as follows:

ms1 = MetricScrew(head="Flat", pitch=2)

Create a flathead screwdriver instance:

sd1 = Screwdriver(head="Flat", length=6)

Turn the screw \(5\) complete clockwise revolutions with the screwdriver and print the resulting angle and depth as follows:

sd1.drive(ms1, 5*2*np.pi)
print(f"Angle: {ms1.angle:.3g} rad \nDepth: {ms1.depth} mm")
<__main__.MetricScrew at 0x11d678750>
Angle: 31.4 rad 
Depth: 10.0 mm

Turn the screw \(3\) complete counterclockwise revolutions with the screwdriver and print the resulting angle and depth as follows:

sd1.drive(ms1, -3*2*np.pi)
print(f"Angle: {ms1.angle:.3g} rad \nDepth: {ms1.depth} mm")
<__main__.MetricScrew at 0x11d678750>
Angle: 12.6 rad 
Depth: 4.0 mm

Create a left-handed MetricScrew instance as follows:

ms2 = MetricScrew(head="Flat", pitch=2, handed="Left")

Turn the ms2 screw \(4\) complete counterclockwise revolutions with the sd1 screwdriver and print the resulting angle and depth of ms2 as follows:

sd1.drive(ms2, -3*2*np.pi)
print(f"Angle: {ms2.angle:.3g} rad \nDepth: {ms2.depth} mm")
<__main__.MetricScrew at 0x11d67a1d0>
Angle: -18.8 rad 
Depth: 6.0 mm

Turn the ms2 screw \(2\) complete clockwise revolutions with the sd1 screwdriver and print the resulting angle and depth of ms2 as follows:

sd1.drive(ms2, 2*2*np.pi)
print(f"Angle: {ms2.angle:.3g} rad \nDepth: {ms2.depth} mm")
<__main__.MetricScrew at 0x11d67a1d0>
Angle: -6.28 rad 
Depth: 2.0 mm

Create an instance sd2 of Screwdriver with a hex head and try to turn the sd1 screw and catch and print the exception as follows:

sd2 = Screwdriver(head="Hex", length=6)
try:
    sd2.drive(ms1, 1)  # Should raise an exception
except Exception as err:
    print(f"Unexpected {type(err)}: {err}")  # Print the exception
Unexpected <class 'TypeError'>: Hex screwdriver can't turn a Flat screw.

Improve the bubble sort algorithm of by adding a test that can return the list if it is sorted before completing all the loops. Implement the improved bubble sort algorithm in a program that it meets the following requirements:

  1. It defines a function bubble_sort(l: list) -> list that implements the bubble sort algorithm.
  2. It demonstrates the bubble_sort() function works on three different lists of numbers.
  3. It demonstrates that the early return functionality, in fact, saves us from making extra passes through the list.

A more efficient bubble sort algorithm is given in .

Algorithm : Pseudocode for a more efficient bubble sort algorithm.
Algorithm

The following program meets the requirements:

""""Part of the Solution to Chapter 2 Problem VX"""

# %% [markdown]
## Introduction
# The program requirements specify a single function bubble_sort()
# be defined. It will be defined in the following section and tested
# on three lists afterward.
# %% [markdown]
## Function Definition
# %%
def bubble_sort(l: list) -> list:
    """Returns a list sorted smallest to largest."""
    n: int = len(l)
    ls: list = l.copy()  # Init. sorted list (because mutable)
    for i in range(0, n - 1):  # Pass through list n-1 times
        swapped: bool = False  # Init. swapped test (early return)
        for j in range(
            0, n - i - 1
        ):  # Pass through potentially unsorted elements
            if ls[j] > ls[j + 1]:
                jp1 = ls.pop(j + 1)
                ls.insert(j, jp1)
                swapped = True
        if not swapped:
            print(f"Early return! Had {n - i} passes left.")
            return ls  # Return early
    return ls


# %% [markdown]
## Call Function and Print
# %%
test_lists = [
    [4, 2, 6, 1, 9],
    [3.0, -1.0, 10.0, -33.0],
    [1, 2, 3, 4, 5, 3],
    [5, 4, 3, 2, 1, 0],
]

for test_list in test_lists:
    print(f"Sorted {test_list} into {bubble_sort(test_list)}")

This program prints the following to the console:

Early return! Had 2 passes left.
Sorted [4, 2, 6, 1, 9] into [1, 2, 4, 6, 9]
Sorted [3.0, -1.0, 10.0, -33.0] into [-33.0, -1.0, 3.0, 10.0]
Early return! Had 4 passes left.
Sorted [1, 2, 3, 4, 5, 3] into [1, 2, 3, 3, 4, 5]
Sorted [5, 4, 3, 2, 1, 0] into [0, 1, 2, 3, 4, 5]

The lists are properly sorted. Note that in two cases the early return has occurred, as we can see by the early return messages. This demonstrates that more passes would have been performed without the early return logic.

Preprogramming work: In this problem, before writing the program specified, (1) draw a functional design method diagram (see subsection 2.7.1) and (2) write a pseudocode for each function (see subsection 2.7.2).

Restrictions: In this problem, most of the functions you will write already exist in the standard libary module statistics. You may not use this module for this problem, but you may use others, such as the math module. You may also use list methods such as sort(). Furthermore, you may not use any external packages.

Programming: Write a program in a single script that meets the following requirements:

  1. It defines a function stats(x: list) -> dict that computes the following basic statistics for input list x of real numbers:
    1. The sample mean; for a list \(x\) of \(n\) values, the sample mean \(m\) is \[m(x) = \frac{1}{n}\sum_{i=0}^{n-1} x_i.\]
    2. The sample variance; the sample variance \(s^2\) is \[s^2(x) = \frac{1}{n-1}\sum_{i=0}^{n-1} \left(x_i - m(x)\right)^2.\]
    3. The sample standard deviation; the sample standard deviation \(s\) is \[s(x) = \sqrt{s^2(x)}.\]
    4. The median; the median \(M\) of a sorted list \(x\) of \(n\) numbers is value of the list at index \(i_M = (n-1)/2\) (i.e., the middle index); more precisely, \[ M(x) = \begin{cases} x_{i_M} & i_M\text{ is an integer} \\ \frac{1}{2}\left(x_{\lfloor i_M \rfloor} + x_{\lceil i_M \rceil}\right) & \text{otherwise} \end{cases} \] where \(\lfloor \cdot \rfloor\) is the floor function that rounds down and \(\lceil \cdot \rceil\) is the ceiling function that rounds up. So in the case that there is no middle index, the mode is the mean of the two middle values.
    The stats() function should return a dict with the keys "mean", "var", "std", and "median" correspond to values for the computed sample mean, variance, standard deviation, and median.
  2. It demonstrates the stats() function works on three different lists of numbers.

The functional analysis is summarized in the block diagram of fig. ¿fig:ys-functional-diagram?.

 Figure
Figure : Functional analysis diagram.

, , , , show pseudocode for each function.

Algorithm : Pseudocode for the stats() function.
Algorithm
Algorithm : Pseudocode for the mean() function.
Algorithm
Algorithm : Pseudocode for the var() function.
Algorithm
Algorithm : Pseudocode for the std() function.
Algorithm
Algorithm : Pseudocode for the median() function.
Algorithm

The following program meets the requirements:

""""Part of the Solution to Chapter 2 Problem YS"""
import math
from pprint import pprint

# %% [markdown]
## Introduction
# The program will consist of the five functions identified in the
# functional analysis diagram. The pseudocode for each function will
# guide the writing of the functions. The functions are defined in
# the following section and they are tested in the last section.
# %% [markdown]
## Function Definitions
# %%
def mean(x: list) -> float:
    """Returns the mean of a numeric list x."""
    s: float = sum(x)  # Sum of items in list
    n: int = len(x)  # Number of elements in list
    return s / n


def var(x: list, mean_val: float = None) -> float:
    """Returns the sample variance of x.
    Will compute the mean if it isn't supplied
    """
    if mean_val is None:
        mean_val = mean()
    summand = []  # Initialize the summand list
    for xi in x:
        summand.append((xi - mean_val) ** 2)
    s = sum(summand)
    n = len(summand)
    return s / (n - 1)


def std(var_val: float) -> float:
    """Computes the standard deviation from the variance."""
    return math.sqrt(var_val)


def median(x: list) -> float:
    """Returns the median of list x."""
    x_s: list = sorted(x)  # New list
    n: int = len(x_s)
    i_m: float = (n - 1) / 2.0  # Nominal middle index
    if i_m.is_integer():
        med_val = x[int(i_m)]  # Middle value
    else:
        x_low = x[math.floor(i_m)]
        x_high = x[math.ceil(i_m)]
        med_val = (x_low + x_high) / 2  # Mean of middle values
    return med_val


def stats(x: list) -> dict:
    """Returns a dict with the sample mean, variance,
    standard deviation, and median.
    """
    d = {}
    d["mean"] = mean(x)
    d["var"] = var(x, d["mean"])
    d["std"] = std(d["var"])
    d["median"] = median(x)
    return d


# %% [markdown]
## Call Functions and Print
# %%
test_lists = [
    list(range(0, 11)),
    [3.0, -1.0, 10.0, -33.0],
    [1, 2, 3, 4, 5, 3],
]

for test_list in test_lists:
    print(f"Stats for {test_list}:")
    pprint(stats(test_list), width=1)

This program prints the following to the console:

Stats for [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
{'mean': 5.0,
 'median': 5,
 'std': 3.3166247903554,
 'var': 11.0}
Stats for [3.0, -1.0, 10.0, -33.0]:
{'mean': -5.25,
 'median': 4.5,
 'std': 19.05037182489273,
 'var': 362.9166666666667}
Stats for [1, 2, 3, 4, 5, 3]:
{'mean': 3.0,
 'median': 3.5,
 'std': 1.4142135623730951,
 'var': 2.0}

  1. A right-handed screw with thread pitch \(p\) (mm), turned clockwise an angle \(\alpha\) (rad), advances forward \(\ell = p \alpha/(2\pi)\) mm. A full turn (i.e., \(\alpha = 2 \pi\)) advances the screw \(\ell = p\) mm. Treat clockwise turns as positive angles.↩︎

Online Resources for Section 2.8

No online resources.