{ "cells": [ { "cell_type": "markdown", "id": "b01565c8", "metadata": {}, "source": [ "### Functions and Scope\n", "\n", "What happens when the following code is run?" ] }, { "cell_type": "code", "execution_count": 1, "id": "301a65c4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "testfun1 (generic function with 1 method)" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var1 = 10;\n", "\n", "function testfun1()\n", " var1 = 20;\n", " return 0\n", "end" ] }, { "cell_type": "code", "execution_count": 2, "id": "5e409817", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var1" ] }, { "cell_type": "code", "execution_count": 3, "id": "aea3558a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "testfun1()" ] }, { "cell_type": "code", "execution_count": 4, "id": "7621be1f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var1" ] }, { "cell_type": "markdown", "id": "5d1075bf", "metadata": {}, "source": [ "Julia functions in general do not mutate the state of variables. So here even though inside the function there is also a variable with the same name, it does not change the outside value.\n", "\n", "If you want to change the outside value:\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "0181b982", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "testfun2! (generic function with 1 method)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function testfun2!()\n", " global var1\n", " var1 = 20;\n", " return 0\n", "end" ] }, { "cell_type": "code", "execution_count": 6, "id": "94d2c49f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "testfun2!()" ] }, { "cell_type": "code", "execution_count": 7, "id": "38c461b7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "20" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var1" ] }, { "cell_type": "markdown", "id": "95134517", "metadata": {}, "source": [ "The convention with julia is that mutating functions end in an `!`. This is true for other standard julia library functions too (e.g. `push!()`, etc.)" ] }, { "cell_type": "markdown", "id": "f51486ab", "metadata": {}, "source": [ "### Conditionals" ] }, { "cell_type": "code", "execution_count": 8, "id": "8421afc8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "isOdd (generic function with 1 method)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function isOdd( x::Int64 )\n", " \n", " if x % 2 == 1\n", " return true\n", " else\n", " return false\n", " end\n", " \n", "end" ] }, { "cell_type": "code", "execution_count": 9, "id": "850cb643", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "false" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isOdd(4)" ] }, { "cell_type": "markdown", "id": "3c814012", "metadata": {}, "source": [ "Let's try with more cases. How would you code up the function:\n", "\n", "$$\n", " f(x) = \\begin{cases}\n", " 0 ~ &x = 0 \\\\\n", " \\cos(x) ~ &x > 0 \\\\\n", " -1-x ~ &x < 0\n", " \\end{cases}\n", "$$" ] }, { "cell_type": "code", "execution_count": 10, "id": "0a6b70ad", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "func2 (generic function with 1 method)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function func2( x )\n", " \n", " if x == 0\n", " return 0\n", " elseif x > 0\n", " return cos(x)\n", " else\n", " return -1-x\n", " end\n", " \n", "end" ] }, { "cell_type": "markdown", "id": "3dbb24cb", "metadata": {}, "source": [ "However let's try something:" ] }, { "cell_type": "code", "execution_count": 11, "id": "980cfbb5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "func3 (generic function with 1 method)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function func3( x )\n", " \n", " #Quadratic polynomial with roots at 0.1, -4.3\n", " return x^2 + 4.2x - 0.43\n", " \n", "end" ] }, { "cell_type": "code", "execution_count": 12, "id": "1b9f069e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.551115123125783e-17" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "func3(0.1)" ] }, { "cell_type": "code", "execution_count": 13, "id": "e8492150", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "func2(func3(0.1))" ] }, { "cell_type": "markdown", "id": "a2a9ecf9", "metadata": {}, "source": [ "What happened? This is a problem with cutoff, floating numbers in computers in general are not stored exactly - they are cutoff after a certain number of digits. This can introduce errors in computing as we see here. How can we fix this?" ] }, { "cell_type": "code", "execution_count": 14, "id": "7ed5d2f9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "func2fix (generic function with 1 method)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function func2fix( x )\n", " \n", " if abs(x) < 1e-12\n", " return 0\n", " elseif x > 1e-12\n", " return cos(x)\n", " else\n", " return -1-x\n", " end\n", " \n", "end" ] }, { "cell_type": "code", "execution_count": 15, "id": "ffb42a23", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "func2fix(func3(0.1))" ] }, { "cell_type": "markdown", "id": "6f02bd29", "metadata": {}, "source": [ "This is a common trick in mathematical computing, sometimes to get the right answer you have to introduce a small error into the function due to numerical inaccuracies. " ] }, { "cell_type": "markdown", "id": "299f0971", "metadata": {}, "source": [ "### Boolean operations\n", "\n", "An important tool when it comes to conditionals are the boolean operations `&&`, `||`, `~` (AND, OR, NOT)" ] }, { "cell_type": "code", "execution_count": 16, "id": "fee3da1b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "true && true" ] }, { "cell_type": "code", "execution_count": 17, "id": "72c4986f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "false" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "true && false" ] }, { "cell_type": "code", "execution_count": 18, "id": "8acb734b", "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "true || false" ] }, { "cell_type": "code", "execution_count": 19, "id": "98a46fde", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "isPositiveEven (generic function with 1 method)" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function isPositiveEven(x)\n", " \n", " if x % 2 == 0 && x > 0\n", " return true \n", " end\n", " return false\n", " \n", "end" ] }, { "cell_type": "code", "execution_count": 20, "id": "76783a3b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "false" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isPositiveEven(-4)" ] }, { "cell_type": "code", "execution_count": 21, "id": "ac3015b5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isPositiveEven(4)" ] }, { "cell_type": "markdown", "id": "206c529f", "metadata": {}, "source": [ "### For loops and While loops\n", "\n", "This is how iteration works in most languages including Julia. If you come from taking CS61A, I know they teach you recursion as a prime tool for doing this. I have **very** strong opinions on this (which is also actually somewhat shared in industry) in that recursion is almost always the worst way to do iteration. This is because it is memory intensive and often far far slower than a standard for or while loop." ] }, { "cell_type": "code", "execution_count": 22, "id": "e1dca68e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "func4 (generic function with 1 method)" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function func4( x )\n", " \n", " tot = 0;\n", " for i = 1:x\n", " tot += x;\n", " end\n", " return tot\n", " \n", "end" ] }, { "cell_type": "code", "execution_count": 23, "id": "418fb38d", "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "100" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "func4( 10 )" ] }, { "cell_type": "markdown", "id": "b72302d0", "metadata": {}, "source": [ "For loops and while loops are largely equivalent, use whichever is more convenient for the task at hand:" ] }, { "cell_type": "code", "execution_count": 24, "id": "7e171170", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "func5bad (generic function with 1 method)" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function func5bad( x )\n", " tot = 0; counter = 0;\n", " while counter < x\n", " tot += x; \n", " end\n", " return tot\n", "end" ] }, { "cell_type": "markdown", "id": "7702552c", "metadata": {}, "source": [ "Why is the above function bad? The `counter` variable is never updated, so the while loop never stops - this is called an infinite loop. How to fix this?" ] }, { "cell_type": "code", "execution_count": 25, "id": "0b6ddb21", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "func5 (generic function with 1 method)" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function func5( x )\n", " tot = 0; counter = 0;\n", " while counter < x\n", " tot += x;\n", " counter += 1;\n", " end\n", " return tot\n", "end" ] }, { "cell_type": "code", "execution_count": 26, "id": "ff341192", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "100" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "func5(10)" ] }, { "cell_type": "markdown", "id": "6a4df8d8", "metadata": {}, "source": [ "### Practice Question!" ] }, { "cell_type": "markdown", "id": "ea6020bc", "metadata": {}, "source": [ "Predict the outcome of the following code:" ] }, { "cell_type": "code", "execution_count": 27, "id": "208d2663", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "weirdFn (generic function with 1 method)" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function weirdFn( x,y )\n", " \n", " for i = 1:5\n", " x /= 2;\n", " y -= 3;\n", " if x < 2 || y < 0\n", " return x,y \n", " end\n", " end\n", " return x,y\n", " \n", "end" ] }, { "cell_type": "code", "execution_count": 28, "id": "99b19b2e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1.0, 88)" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "weirdFn( 16,100 )" ] }, { "cell_type": "code", "execution_count": 29, "id": "bd1ab59f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(2.0, -1)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "weirdFn( 16,8 )" ] }, { "cell_type": "markdown", "id": "df0d1cc9", "metadata": {}, "source": [ "Write a function to generate the nth Fibonacci number: (1,1,2,3,5,8,...) the next number is sum of previous two numbers" ] }, { "cell_type": "code", "execution_count": 30, "id": "935e963d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "fibonacci (generic function with 1 method)" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function fibonaccihelper( a,b )\n", " \n", " return b, a+b\n", " \n", "end\n", "\n", "function fibonacci( x )\n", " \n", " if x == 1 || x == 2\n", " return 1\n", " end\n", " \n", " a = 1; b = 1;\n", " for i = 2:x\n", " a,b = fibonaccihelper( a,b );\n", " end\n", " \n", " return b\n", " \n", "end" ] }, { "cell_type": "code", "execution_count": 31, "id": "f459f6db", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fibonacci(5)" ] }, { "cell_type": "code", "execution_count": null, "id": "29f5652a", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.6.5", "language": "julia", "name": "julia-1.6" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.6.5" } }, "nbformat": 4, "nbformat_minor": 5 }