--- jupytext: text_representation: extension: .md format_name: myst format_version: 0.13 jupytext_version: 1.10.3 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 --- +++ {"slideshow": {"slide_type": "slide"}} # Calculators +++ {"slideshow": {"slide_type": "-"}, "tags": ["remove-cell"]} **CS1302 Introduction to Computer Programming** ___ ```{code-cell} ipython3 --- hide_input: false init_cell: true slideshow: slide_type: '-' --- import math from math import cos, exp, log, pi, sin, tan import matplotlib.pyplot as plt import numpy as np from ipywidgets import interact # interactive plot with ipympl %matplotlib widget ``` +++ {"slideshow": {"slide_type": "subslide"}} The following code is a Python one-liner that creates a calculator. - Evaluate the cell with `Ctrl+Enter`. - Enter `1+1` and see the result. ```{code-cell} ipython3 --- slideshow: slide_type: '-' tags: [remove-output] --- print(eval(input())) ``` +++ {"slideshow": {"slide_type": "fragment"}} ````{tip} Try some calculations below using this calculator: 1. $2^3$ by entering `2**3`; 1. $\frac23$ by entering `2/3`; 1. $\left\lceil\frac32\right\rceil$ by entering `3//2`; 1. $3\mod 2$ by entering `3%2`; 1. $\sqrt{2}$ by entering `2**0.5`; and 1. $\sin(\pi/6)$ by entering `sin(pi/6)`; ```` +++ {"slideshow": {"slide_type": "fragment"}} For this lab, you will create more powerful and dedicated calculators. We will first show you a demo. Then, it will be your turn to create the calculators. +++ {"slideshow": {"slide_type": "slide"}} ## Hypotenuse Calculator +++ {"slideshow": {"slide_type": "fragment"}} ````{prf:proposition} By the Pythagoras theorem, given a right-angled triangle, ![Right-angled triangle](images/pythagoras.dio.svg) the length of the hypotenuse is $$ c = \sqrt{a^2 + b^2} $$ (hypotenuse) where $a$ and $b$ are the lengths of the other sides of the triangle. ```` +++ We can define the following function to calculate the length `c` of the hypotenuse when given the lengths `a` and `b` of the other sides: ```{code-cell} ipython3 --- slideshow: slide_type: fragment --- def length_of_hypotenuse(a, b): c = (a**2 + b**2)**(0.5) # Pythagoras return c ``` +++ {"slideshow": {"slide_type": "fragment"}} ````{important} You need not understand how a function is defined, but - you should know how to *write the formula {eq}`hypotenuse` as a Python expression* using the exponentiation operator `**`, and - *assign the variable* `c` the value of the expression (Line 2) using the assignment operator `=`. ```` +++ {"slideshow": {"slide_type": "subslide"}} For example, you may be asked to write Line 2, while Line 1 and 3 are given to you: +++ {"slideshow": {"slide_type": "fragment"}} **Exercise** Complete the function below to return the length `c` of the hypotenuse given the lengths `a` and `b`. ```{code-cell} ipython3 --- deletable: false nbgrader: cell_type: code checksum: 07e9bf0ce74ed11e07ad5f772a79f6b8 grade: false grade_id: length_of_hypotenuse locked: false schema_version: 3 solution: true task: false slideshow: slide_type: '-' tags: [remove-output] --- def length_of_hypotenuse(a, b): # YOUR CODE HERE raise NotImplementedError() return c ``` +++ {"slideshow": {"slide_type": "fragment"}} ````{caution} - Complete the above exercise to get the credit even though the answer was already revealed as a demo. Instead of copy-and-paste the answer, type it yourself. - Note that indentation affects the execution of Python code. In particular, the assignment statement must be indented to indicate that it is part of the *body* of the function. ```` +++ {"slideshow": {"slide_type": "subslide"}} We will use `ipywidgets` to let user interact with the calculator more easily: - After running the cell, move the sliders to change the values of `a` and `b`. - Observer that the value of `c` is updated immediately. ```{code-cell} ipython3 --- code_folding: [] slideshow: slide_type: '-' tags: [remove-output] --- # hypotenuse calculator @interact(a=(0, 10, 1), b=(0, 10, 1)) def calculate_hypotenuse(a=3, b=4): print("c: {:.2f}".format(length_of_hypotenuse(a, b))) ``` +++ {"slideshow": {"slide_type": "fragment"}} ````{important} You need not know how to write widgets, but you should know how to *format a floating point number* (Line 3). ```` +++ {"slideshow": {"slide_type": "subslide"}} You can check your code with a few cases listed in the test cell below. ```{code-cell} ipython3 --- code_folding: [] deletable: false editable: false nbgrader: cell_type: code checksum: f52b93d815cfd306fae374ec4d8a58c4 grade: true grade_id: test-length_of_hypotenuse locked: true points: 1 schema_version: 3 solution: false task: false slideshow: slide_type: '-' tags: [remove-output] --- # tests def test_length_of_hypotenuse(a, b, c): c_ = length_of_hypotenuse(a, b) correct = math.isclose(c, c_) if not correct: print(f"For a={a} and b={b}, c should be {c}, not {c_}.") assert correct test_length_of_hypotenuse(3, 4, 5) test_length_of_hypotenuse(0, 0, 0) test_length_of_hypotenuse(4, 7, 8.06225774829855) ``` +++ {"slideshow": {"slide_type": "slide"}} ## Quadratic equation +++ {"slideshow": {"slide_type": "subslide"}} ### Graphical calculator for parabola +++ ![Parabola calculator](images/parabola.dio.svg) +++ {"slideshow": {"slide_type": "subslide"}} ````{prf:definition} Parabola The collection of points $(x,y)$ satisfying the following equation forms a *parabola*: $$ y=ax^2+bx+c $$ (parabola) where $a$, $b$, and $c$ are real numbers called the *coefficients*. ```` +++ {"slideshow": {"slide_type": "fragment"}} **Exercise** Given the variables `x`, `a`, `b`, and `c` store the $x$-coordinate and the coefficients $a$, $b$, and $c$ respectively, assign `y` the corresponding $y$-coordinate of the parabola {eq}`parabola`. ```{code-cell} ipython3 --- deletable: false nbgrader: cell_type: code checksum: 2c86fa4ce83bcbe0906f9b64b5c1a032 grade: false grade_id: get_y locked: false schema_version: 3 solution: true task: false slideshow: slide_type: '-' tags: [remove-output] --- def get_y(x, a, b, c): # YOUR CODE HERE raise NotImplementedError() return y ``` To test your code: ```{code-cell} ipython3 --- code_folding: [] deletable: false editable: false nbgrader: cell_type: code checksum: 4d00403723b0578d72ce900068e343fa grade: true grade_id: test-get_y locked: true points: 1 schema_version: 3 solution: false task: false slideshow: slide_type: fragment tags: [remove-output] --- # tests def test_get_y(y, x, a, b, c): y_ = get_y(x, a, b, c) correct = math.isclose(y, y_) if not correct: print(f"With (x, a, b, c)={x,a,b,c}, y should be {y} not {y_}.") assert correct test_get_y(0, 0, 0, 0, 0) test_get_y(1, 0, 1, 2, 1) test_get_y(2, 0, 2, 1, 2) ``` ```{code-cell} ipython3 --- deletable: false editable: false nbgrader: cell_type: code checksum: 0adfafae7b0307eb4e3a7be0bd936147 grade: true grade_id: htest-get_y locked: true points: 1 schema_version: 3 solution: false task: false tags: [remove-cell] --- # hidden tests ``` To run the graphical calculator: ```{code-cell} ipython3 --- code_folding: [] slideshow: slide_type: subslide tags: [remove-output] --- # graphical calculator for parabola fig, ax = plt.subplots() xmin, xmax, ymin, ymax, resolution = -10, 10, -10, 10, 50 x = np.linspace(xmin, xmax, resolution) ax.set_title(r'$y=ax^2+bx+c$') ax.set_xlabel(r'$x$') ax.set_ylabel(r'$y$') ax.set_xlim([xmin, xmax]) ax.set_ylim([ymin, ymax]) ax.grid() p, = ax.plot(x, get_y(x, 0, 0, 0)) @interact(a=(-10, 10, 1), b=(-10, 10, 1), c=(-10, 10, 1)) def plot_parabola(a, b, c): p.set_ydata(get_y(x, a, b, c)) ``` +++ {"slideshow": {"slide_type": "slide"}} ### Quadratic equation solver +++ {"slideshow": {"slide_type": "-"}} ![quadratic equtaion solver](images/quadratic.dio.svg) +++ {"slideshow": {"slide_type": "subslide"}} ````{prf:proposition} For the quadratic equation $$ ax^2+bx+c=0, $$ (quadratic) the *roots* (solutions for $x$) are give by $$ \frac{-b-\sqrt{b^2-4ac}}{2a},\frac{-b+\sqrt{b^2-4ac}}{2a}. $$ (quadratic_roots) ```` +++ {"slideshow": {"slide_type": "fragment"}} **Exercise** Assign to `root1` and `root2` the values of the first and second roots above respectively. ```{code-cell} ipython3 --- deletable: false nbgrader: cell_type: code checksum: ac8d52d2f7328a894d73bce80d19dafc grade: false grade_id: get_roots locked: false schema_version: 3 solution: true task: false slideshow: slide_type: fragment tags: [remove-output] --- def get_roots(a, b, c): # YOUR CODE HERE raise NotImplementedError() return root1, root2 ``` To test your code: ```{code-cell} ipython3 --- code_folding: [] deletable: false editable: false nbgrader: cell_type: code checksum: cd703af7ee4d214a1588e34c86a832eb grade: true grade_id: test-get_roots locked: true points: 1 schema_version: 3 solution: false task: false slideshow: slide_type: fragment tags: [remove-output] --- # tests def test_get_roots(roots, a, b, c): def mysort(c): return c.real, c.imag roots_ = get_roots(a, b, c) assert np.isclose(sorted(roots, key=mysort), sorted(roots_, key=mysort)).all() test_get_roots((-1.0, 0.0), 1, 1, 0) test_get_roots((-1.0, -1.0), 1, 2, 1) test_get_roots((-2.0, -1.0), 1, 3, 2) test_get_roots([(-0.5-0.5j), (-0.5+0.5j)], 2, 2, 1) ``` ```{code-cell} ipython3 --- deletable: false editable: false nbgrader: cell_type: code checksum: 79a531007ec3cae77b0a47be0ba9710c grade: true grade_id: htest-get_roots locked: true points: 1 schema_version: 3 solution: false task: false tags: [remove-cell] --- # hidden tests ``` To run the calculator: ```{code-cell} ipython3 --- code_folding: [0] slideshow: slide_type: fragment tags: [remove-output] --- # quadratic equations solver @interact(a=(-10,10,1),b=(-10,10,1),c=(-10,10,1)) def quadratic_equation_solver(a=1,b=2,c=1): print('Roots: {}, {}'.format(*get_roots(a,b,c))) ``` +++ {"slideshow": {"slide_type": "slide"}} ## Number conversion +++ {"slideshow": {"slide_type": "subslide"}} ### Byte-to-Decimal calculator +++ {"slideshow": {"slide_type": "-"}} ![byte-to-decimal](images/byte-to-decimal.dio.svg) +++ {"slideshow": {"slide_type": "subslide"}} Denote a binary number stored in a byte ($8$ bits) as $$ b_7\circ b_6\circ b_5\circ b_4\circ b_3\circ b_2\circ b_1\circ b_0, $$ where $\circ$ concatenates $b_i$'s together into a binary string. +++ {"slideshow": {"slide_type": "fragment"}} The binary string can be converted to a decimal number by the formula $$ b_7\cdot 2^7 + b_6\cdot 2^6 + b_5\cdot 2^5 + b_4\cdot 2^4 + b_3\cdot 2^3 + b_2\cdot 2^2 + b_1\cdot 2^1 + b_0\cdot 2^0. $$ +++ {"slideshow": {"slide_type": "fragment"}} E.g., the binary string `'11111111'` is the largest integer represented by a byte: $$ 2^7+2^6+2^5+2^4+2^3+2^2+2^1+2^0=255=2^8-1. $$ +++ {"slideshow": {"slide_type": "fragment"}} **Exercise** Assign to `decimal` the *integer* value represented by the binary sequence `b7,b6,b5,b4,b3,b2,b1,b0` of *characters* `'0'` or `'1'`. ```{code-cell} ipython3 --- deletable: false nbgrader: cell_type: code checksum: 9e002976b002de6304164af3ad806f43 grade: false grade_id: byte_to_decimal locked: false schema_version: 3 solution: true task: false slideshow: slide_type: fragment tags: [remove-output] --- def byte_to_decimal(b7, b6, b5, b4, b3, b2, b1, b0): """ Parameters: ----------- b7, ..., b0 are single characters either '0' or '1'. """ # YOUR CODE HERE raise NotImplementedError() return decimal ``` To test your code: ```{code-cell} ipython3 --- code_folding: [] deletable: false editable: false nbgrader: cell_type: code checksum: 030e6a4746ee213dd7febd09db3d7680 grade: true grade_id: test-byte_to_decimal locked: true points: 1 schema_version: 3 solution: false task: false slideshow: slide_type: fragment tags: [remove-output] --- # tests def test_byte_to_decimal(decimal, b7, b6, b5, b4, b3, b2, b1, b0): decimal_ = byte_to_decimal(b7, b6, b5, b4, b3, b2, b1, b0) assert decimal == decimal_ and isinstance(decimal_, int) test_byte_to_decimal(38, '0', '0', '1', '0', '0', '1', '1', '0') test_byte_to_decimal(20, '0', '0', '0', '1', '0', '1', '0', '0') test_byte_to_decimal(22, '0', '0', '0', '1', '0', '1', '1', '0') ``` ```{code-cell} ipython3 --- deletable: false editable: false nbgrader: cell_type: code checksum: 368a00935ff0f11755434b00e27eeaff grade: true grade_id: htest-byte_to_decimal locked: true points: 1 schema_version: 3 solution: false task: false tags: [remove-cell] --- # hidden tests ``` To run the calculator: ```{code-cell} ipython3 :code_folding: [0] :tags: [remove-output] # byte-to-decimal calculator bit = ['0', '1'] @interact(b7=bit, b6=bit, b5=bit, b4=bit, b3=bit, b2=bit, b1=bit, b0=bit) def convert_byte_to_decimal(b7, b6, b5, b4, b3, b2, b1, b0): print('decimal:', byte_to_decimal(b7, b6, b5, b4, b3, b2, b1, b0)) ``` +++ {"slideshow": {"slide_type": "subslide"}} ### Decimal-to-Byte calculator +++ {"slideshow": {"slide_type": "-"}} ![decimal-to-byte](images/decimal-to-byte.dio.svg) +++ {"slideshow": {"slide_type": "subslide"}} **Exercise** Assign to `byte` a *string of 8 bits* that represents the value of `decimal`, a non-negative decimal integer from $0$ to $2^8-1=255$. *Hint: Use `//` and `%`.* ```{code-cell} ipython3 --- deletable: false nbgrader: cell_type: code checksum: 9de8a3c79ad6c5af5db8a55ce33675e4 grade: false grade_id: decimal_to_byte locked: false schema_version: 3 solution: true task: false slideshow: slide_type: '-' tags: [remove-output] --- def decimal_to_byte(decimal): # YOUR CODE HERE raise NotImplementedError() return byte ``` To test your code: ```{code-cell} ipython3 --- code_folding: [] deletable: false editable: false nbgrader: cell_type: code checksum: 216c2407ac5231bc82b9d61a1ec8a628 grade: true grade_id: test-decimal_to_byte locked: true points: 1 schema_version: 3 solution: false task: false slideshow: slide_type: fragment tags: [remove-output] --- # tests def test_decimal_to_byte(byte,decimal): byte_ = decimal_to_byte(decimal) assert byte == byte_ and isinstance(byte, str) and len(byte) == 8 test_decimal_to_byte('01100111', 103) test_decimal_to_byte('00000011', 3) test_decimal_to_byte('00011100', 28) ``` ```{code-cell} ipython3 --- deletable: false editable: false nbgrader: cell_type: code checksum: 7f8a949776449868af9155c44585aa19 grade: true grade_id: htest-decimal_to_byte locked: true points: 1 schema_version: 3 solution: false task: false tags: [remove-cell] --- # hidden tests ``` To run the calculator: ```{code-cell} ipython3 --- code_folding: [0] slideshow: slide_type: fragment tags: [remove-output] --- # decimal-to-byte calculator @interact(decimal=(0,255,1)) def convert_decimal_to_byte(decimal=0): print('byte:', decimal_to_byte(decimal)) ``` +++ {"tags": []} ## Symbolic calculator (optional) +++ Can we do complicated arithmetics with Python. What about Calculus? +++ $$ \int \tan(x)\, dx = \color{red}{?} $$ +++ Solution: +++ ````{tip} - Take a look at the different panels to learn about the solution: `Steps`, `Plot`, and `Derivative`. - Try different [random examples](https://gamma.sympy.org/). ```` +++ **How does SymPy Gamma work?** +++ [SymPy Gamma](https://gamma.sympy.org/) is a web application running [SymPy](https://docs.sympy.org/latest/index.html), which is a python library for symbolic computation. +++ **How to use SymPy?** +++ To import the library: ```{code-cell} ipython3 import sympy as sp ``` We need to define a symbolic variable and assign it to a python variable. ```{code-cell} ipython3 x = sp.symbols('x') x ``` The SymPy expression for $\tan(x)$ is: ```{code-cell} ipython3 f = sp.tan(x) f ``` To compute the integration: ```{code-cell} ipython3 int_f = sp.integrate(f) int_f ``` To compute the derivative: ```{code-cell} ipython3 diff_int_f = sp.diff(int_f) diff_int_f ``` The answer can be simplified as expected: ```{code-cell} ipython3 diff_int_f.simplify() ``` To plot: ```{code-cell} ipython3 p = sp.plot(f, int_f, (x, -sp.pi/4, sp.pi/4)) ``` **Exercise** Try to compute the following in SymPy and in jupyter notebook: - $\frac{d}{dx} x^x$ - $\frac{d}{dx} \frac{1}{\sqrt{1 - x^2}}$. +++ ````{hint} Use `sp.sqrt` or `**(sp.S(1)/2)` for square root instead of `**0.5`. See [SymPy gotchas](https://docs.sympy.org/latest/gotchas.html). ````