Student Instructions | Week 7 | Topics: def, return, docstrings, default args, assertions
Oregon State University | ENGR 103 | Dr. Cheng Li
What is wrong with this code? Fix it.
Type and run this code:
def calculate_power(V, I)
power = V * I * 1000
Print(power)
calculate_power(0.45 0.020)Find and fix all errors (there are 4). List each error and your fix on the lines below.
Type and run each snippet.
This function adds up the powers of a number: 1 + base + baseยฒ + โฆ + base^n. It uses a for loop inside a def. Type and run this code:
def power_sum(base, n):
"""
Compute 1 + base + base^2 + ... + base^n.
Args:
base : The base number
n : Highest exponent (must be >= 0)
Returns:
float: Sum of the (n+1) terms
"""
assert n >= 0, f'n must be >= 0, got {n}'
total = 0.0
for i in range(n + 1):
total += base ** i
return total
# Test: base=2 gives 1 + 2 + 4 + 8 + ...
for n in range(0, 6):
s = power_sum(2, n)
print(f'n={n}: power_sum(2, {n}) = {s:.0f}')
# Read the docstring
help(power_sum)What happens when you call power_sum(2, -1)? What does the AssertionError message say? Why is that check useful?
The vertex of a parabola y = axยฒ + bx + c is at x = โb/(2a). The decimals parameter shows how to give an argument a default value. Type and run this code:
def parabola_vertex(a, b, c, decimals=4):
"""
Compute the vertex of y = ax^2 + bx + c.
Args:
a : Coefficient of x^2 (must be non-zero)
b : Coefficient of x
c : Constant term
decimals : Decimal places for rounding (default 4)
Returns:
tuple: (x_vertex, y_vertex)
"""
assert a != 0, f'a must be non-zero, got {a}'
assert decimals >= 0, f'decimals must be >= 0, got {decimals}'
x_v = -b / (2 * a)
y_v = a * x_v**2 + b * x_v + c
return round(x_v, decimals), round(y_v, decimals)
# Using the default (4 decimal places)
x_v, y_v = parabola_vertex(1, -6, 5)
print(f'y = x^2 - 6x + 5: vertex at ({x_v}, {y_v})')
# Overriding the default to 2 decimal places
x_v, y_v = parabola_vertex(2, 4, 1, 2)
print(f'y = 2x^2 + 4x + 1: vertex at ({x_v}, {y_v})')
x_v, y_v = parabola_vertex(-1, 4, 0, 2)
print(f'y = -x^2 + 4x: vertex at ({x_v}, {y_v})')Call parabola_vertex(1, -6, 5) and parabola_vertex(1, -6, 5, 2). How does the output differ? Then explain: what is a "default argument" and when is it useful?
One function can call another. Here, quadratic_report calls quadratic_eval and classify_roots. Type and run this code:
def quadratic_eval(a, b, c, x):
"""Evaluate y = ax^2 + bx + c at x."""
return a * x**2 + b * x + c
def classify_roots(a, b, c):
"""Return a string describing the roots of ax^2 + bx + c = 0."""
assert a != 0, f'a must be non-zero, got {a}'
d = b**2 - 4 * a * c
if d > 0:
return 'Two distinct real roots'
elif d == 0:
return 'One repeated real root'
else:
return 'No real roots'
def quadratic_report(label, a, b, c):
"""Print a short analysis of y = ax^2 + bx + c."""
x_v = -b / (2 * a)
y_v = quadratic_eval(a, b, c, x_v) # calls quadratic_eval
print(f'=== {label} ===')
print(f' a={a}, b={b}, c={c}')
print(f' Vertex: ({x_v:.2f}, {y_v:.2f})')
print(f' Roots: {classify_roots(a, b, c)}') # calls classify_roots
quadratic_report('Example A', 1, -6, 5)Call quadratic_report for two more quadratics: one with no real roots (try a=1, b=0, c=4) and one with a repeated root (try a=1, b=2, c=1). What changes in the output each time?
Work in pairs. Build a set of functions for analyzing quadratic polynomials. Every function must have a docstring. Use assert where inputs could be invalid.
Build ALL of these functions with docstrings:
1. poly_eval(a, b, c, x) โ float
Returns: the value of ax^2 + bx + c at x
(No assertion needed โ any numbers are valid inputs)
2. find_vertex(a, b, c) โ tuple
Returns: (x_vertex, y_vertex)
Hint: call poly_eval to compute y_vertex
Assert: a != 0
3. describe_roots(a, b, c) โ str
Returns: 'Two real roots' if b^2 - 4ac > 0
'One real root' if b^2 - 4ac == 0
'No real roots' if b^2 - 4ac < 0
Use if/elif/else. Assert: a != 0
4. opens_toward(a) โ str
Returns: 'upward' if a > 0
'downward' if a < 0
Assert: a != 0
5. print_poly_report(label, a, b, c)
Prints a report by calling the four functions above.
Format (print each line separately):
=== label ===
Coefficients: a=..., b=..., c=...
Vertex: (x_v, y_v)
Opens: upward / downward
Roots: Two real roots / One real root / No real rootsWrap the bisection algorithm from Week 6 inside a def. The formula for the quadratic is computed inline using variables โ no nested functions needed.
Type and run this code:
def bisect_quad(a, b, c, target, lo, hi, eps=1e-6):
"""
Find x in [lo, hi] where ax^2 + bx + c = target, using bisection.
Args:
a, b, c : Quadratic coefficients
target : Target value
lo, hi : Search interval endpoints
eps : Convergence tolerance (default 1e-6)
Returns:
float: x where ax^2 + bx + c is approximately equal to target
"""
assert lo < hi, f'lo must be less than hi, got lo={lo}, hi={hi}'
assert eps > 0, f'eps must be positive, got {eps}'
f_lo = a*lo**2 + b*lo + c - target
f_hi = a*hi**2 + b*hi + c - target
assert f_lo * f_hi < 0, f'No sign change in [{lo}, {hi}] โ bisection cannot find a root'
steps = 0
while abs(hi - lo) > 2 * eps and steps < 200:
mid = (lo + hi) / 2
f_mid = a*mid**2 + b*mid + c - target
f_lo = a*lo**2 + b*lo + c - target
if f_mid * f_lo < 0:
hi = mid
else:
lo = mid
steps += 1
return (lo + hi) / 2
# Find x where x^2 - 6x + 5 = -3 (left root is x = 2)
root = bisect_quad(1, -6, 5, -3, 0.5, 3.0)
print(f'x^2 - 6x + 5 = -3 โ x โ {root:.6f}')
print(f'Verify: {1*root**2 - 6*root + 5:.6f} (should be -3.000000)')
# Call the function for three different targets
print()
r1 = bisect_quad(1, -6, 5, -3, 0.5, 3.0) # left root of x^2-6x+8=0, x=2
r2 = bisect_quad(1, -6, 5, -3, 3.0, 4.5) # right root of x^2-6x+8=0, x=4
r3 = bisect_quad(1, -6, 5, 0, 0.5, 2.0) # left root of x^2-6x+5=0, x=1
print(f'target=-3, left root: x โ {r1:.4f}')
print(f'target=-3, right root: x โ {r2:.4f}')
print(f'target= 0, left root: x โ {r3:.4f}')Call bisect_quad(1, -6, 5, -5, 0.0, 4.0). Read the AssertionError message. Why does it fail? (Hint: from Week 5, what is the minimum value of xยฒ โ 6x + 5?)
Show TA all 5 functions from Part 2. Call print_poly_report('Test-A', 1, -6, 5) and show the output.