{ "cells": [ { "cell_type": "markdown", "id": "a398cc49", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Week I - Key Python Features for Coding Numerical Simulations" ] }, { "cell_type": "markdown", "id": "3b25ff85", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "\n", "## Dynamic typing\n", "\n", "Python is dynamically typed (opposed to static language such as C, C++, Fortran), hence:\n", "\n", "* Types are set on the values, not on the names, of the variables.\n", "* Types do not need to be known before variables are actually used: variable types are checked at run time!\n", "* Variable names can change types if their values are changed\n", "\n", "### Example" ] }, { "cell_type": "code", "execution_count": 1, "id": "31e48d1a", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This object is: \n", "x = 2\n", "This object is: \n", "x = 3.2\n", "This object is: \n", "x = Hello!\n" ] }, { "data": { "text/plain": [ "str" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def inspect(x):\n", " print('This object is: {}'.format(type(x)))\n", " print('x = {}'.format(x))\n", " return type(x)\n", "\n", "x = 2 \n", "inspect(x)\n", "\n", "x = 3.2\n", "inspect(x)\n", "\n", "x = 'Hello!'\n", "inspect(x)\n" ] }, { "cell_type": "markdown", "id": "5d367e84", "metadata": {}, "source": [ "\n", "## Shared references\n", "\n", "Python is *reference counted*, so variables names are just references to the underlying values. How many times a reference is used and what are its related names is counted internally.\n", "Notably, multiple names can reference to the same object: **shared references**\n", "\n", "### Examples\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "bec4246d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4390987328\n", "4390987328\n" ] } ], "source": [ "x = 5\n", "y = x\n", "print(id(x))\n", "print(id(y))" ] }, { "cell_type": "code", "execution_count": 3, "id": "200cf2c6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on built-in function id in module builtins:\n", "\n", "id(obj, /)\n", " Return the identity of an object.\n", " \n", " This is guaranteed to be unique among simultaneously existing objects.\n", " (CPython uses the object's memory address.)\n", "\n" ] } ], "source": [ "help(id)" ] }, { "cell_type": "code", "execution_count": 4, "id": "7c3cf0da", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4390987264\n", "4390987328\n" ] } ], "source": [ "x = 3\n", "print(id(x))\n", "print(id(y))" ] }, { "cell_type": "code", "execution_count": 5, "id": "70780769", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4354254336\n", "4354254368\n" ] } ], "source": [ "y = 4\n", "print(id(x))\n", "print(id(y))" ] }, { "cell_type": "code", "execution_count": 6, "id": "7e674fbb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4391961344\n", "4391961344\n" ] } ], "source": [ "x = ['a','b','c']\n", "y = x\n", "print(id(x))\n", "print(id(y))" ] }, { "cell_type": "code", "execution_count": 7, "id": "ebe8fe75", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['a', 'w', 'c']\n", "['a', 'w', 'c']\n", "4391961344 4391961344\n" ] } ], "source": [ "x[1] = 'w'\n", "print(x)\n", "print(y)\n", "print(id(x),id(y))" ] }, { "cell_type": "markdown", "id": "2e3fbef4", "metadata": {}, "source": [ "## Mutability\n", "\n", "In Python, data types can be either mutable or immutable:\n", "\n", "* **mutable** types allow values to change after creation, such as *lists, dictionaries, sets*\n", "* **immutable** types are static and cannot change values, such as *int, float, bool, str, tuples*\n", "\n", "### Examples" ] }, { "cell_type": "code", "execution_count": 5, "id": "e9e2d5e7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['a', 'b', 'c']\n", "4428701376 4428581696\n", "['a', 'b', 'zz']\n", "4428701376\n" ] } ], "source": [ "lis = ['a','b','c']\n", "tup = ('a','b','c')\n", "print(lis)\n", "print(id(lis),id(tup))\n", "lis[2] = 'zz'\n", "print(lis)\n", "print(id(lis))\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "eba371b0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Forbidden! 'tuple' object does not support item assignment\n" ] } ], "source": [ "try:\n", " tup[2] = 'zz'\n", "except TypeError as err:\n", " print('Forbidden!',err)" ] }, { "cell_type": "markdown", "id": "4ad9adbc", "metadata": {}, "source": [ "\n", "## Integers and Floats in Python\n", "\n", "Several numerical datatypes are available in Python, such as:\n", "* *int*: integers, with unlimited precision!\n", "* *float*: floating points, (usually) implemented with 'double' in C (check with sys.float_info)\n", "* *complex*: two floats (get with z.real and z.imag)\n", "\n", "Other relevant numeric datatypes:\n", "* *fractions.Fraction*, rational number arithmetics \n", "* *decimal.Decimal*, floats with user-definable precision\n", "\n", "Numpy has its own datatypes, here some of the most relevant:\n", "* np.half, np.single, np.double, np.longdouble (depends on platform!)\n", "* np.float16 (alias of np.half), np.float32 (alias of np.single), np.float64 (alias of np.double), np.float128 (alias np.longdouble - existence depends on the platform!)\n", "\n", "For more details on extended precision, beyond 64 bits, check out https://numpy.org/doc/stable/user/basics.types.html#extended-precision" ] }, { "cell_type": "markdown", "id": "e620a8e6", "metadata": {}, "source": [ "-------------" ] }, { "cell_type": "markdown", "id": "ec8f18da", "metadata": {}, "source": [ "\n", "### Week 1, Exercise - Underflow, overflow and machine precision\n" ] }, { "cell_type": "code", "execution_count": 9, "id": "330ee8d6", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "def check_underflow_limit(float_type):\n", " '''\n", " Returns the underflow limit\n", " '''\n", " a = float_type(1.0)\n", " while a>float_type(0.0):\n", " under = a\n", " a = a/float_type(2.0)\n", " print('The calculated underflow limit is:{}'.format(under))\n", "\n", "def check_overflow_limit(float_type):\n", " '''\n", " Returns the overflow limit\n", " '''\n", " a = float_type(1.0)\n", " while a!=float_type('Inf'):\n", " over = a\n", " a = a*float_type(2.0)\n", " print('The calculated overflow limit is:{}'.format(over))\n", "\n", "def check_machine_precision(float_type):\n", " '''\n", " Returns machine precision\n", " '''\n", " eps = float_type(1.0)\n", " while (float_type(1.0)+eps!=float_type(1.0)):\n", " eps = eps/float_type(2.0)\n", " print('The calcuated machine precision is:{}'.format(float_type(2)*eps))\n" ] }, { "cell_type": "code", "execution_count": 11, "id": "121931e7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "The calculated underflow limit is:5e-324\n", "The calculated overflow limit is:8.98846567431158e+307\n", "The calcuated machine precision is:2.220446049250313e-16\n", "---------------\n", "Machine parameters for float64\n", "---------------------------------------------------------------\n", "precision = 15 resolution = 1.0000000000000001e-15\n", "machep = -52 eps = 2.2204460492503131e-16\n", "negep = -53 epsneg = 1.1102230246251565e-16\n", "minexp = -1022 tiny = 2.2250738585072014e-308\n", "maxexp = 1024 max = 1.7976931348623157e+308\n", "nexp = 11 min = -max\n", "smallest_normal = 2.2250738585072014e-308 smallest_subnormal = 4.9406564584124654e-324\n", "---------------------------------------------------------------\n", "\n", "\n", "The calculated underflow limit is:5.960464477539063e-08\n", "The calculated overflow limit is:32768.0\n", "The calcuated machine precision is:0.0009765625\n", "---------------\n", "Machine parameters for float16\n", "---------------------------------------------------------------\n", "precision = 3 resolution = 1.00040e-03\n", "machep = -10 eps = 9.76562e-04\n", "negep = -11 epsneg = 4.88281e-04\n", "minexp = -14 tiny = 6.10352e-05\n", "maxexp = 16 max = 6.55040e+04\n", "nexp = 5 min = -max\n", "smallest_normal = 6.10352e-05 smallest_subnormal = 5.96046e-08\n", "---------------------------------------------------------------\n", "\n", "\n", "The calculated underflow limit is:1.401298464324817e-45\n", "The calculated overflow limit is:1.7014118346046923e+38\n", "The calcuated machine precision is:1.1920928955078125e-07\n", "---------------\n", "Machine parameters for float32\n", "---------------------------------------------------------------\n", "precision = 6 resolution = 1.0000000e-06\n", "machep = -23 eps = 1.1920929e-07\n", "negep = -24 epsneg = 5.9604645e-08\n", "minexp = -126 tiny = 1.1754944e-38\n", "maxexp = 128 max = 3.4028235e+38\n", "nexp = 8 min = -max\n", "smallest_normal = 1.1754944e-38 smallest_subnormal = 1.4012985e-45\n", "---------------------------------------------------------------\n", "\n", "\n", "The calculated underflow limit is:5e-324\n", "The calculated overflow limit is:8.98846567431158e+307\n", "The calcuated machine precision is:2.220446049250313e-16\n", "---------------\n", "Machine parameters for float64\n", "---------------------------------------------------------------\n", "precision = 15 resolution = 1.0000000000000001e-15\n", "machep = -52 eps = 2.2204460492503131e-16\n", "negep = -53 epsneg = 1.1102230246251565e-16\n", "minexp = -1022 tiny = 2.2250738585072014e-308\n", "maxexp = 1024 max = 1.7976931348623157e+308\n", "nexp = 11 min = -max\n", "smallest_normal = 2.2250738585072014e-308 smallest_subnormal = 4.9406564584124654e-324\n", "---------------------------------------------------------------\n", "\n", "\n", "The calculated underflow limit is:5e-324\n", "The calculated overflow limit is:8.98846567431158e+307\n", "The calcuated machine precision is:2.220446049250313e-16\n", "---------------\n", "Machine parameters for float64\n", "---------------------------------------------------------------\n", "precision = 15 resolution = 1.0000000000000001e-15\n", "machep = -52 eps = 2.2204460492503131e-16\n", "negep = -53 epsneg = 1.1102230246251565e-16\n", "minexp = -1022 tiny = 2.2250738585072014e-308\n", "maxexp = 1024 max = 1.7976931348623157e+308\n", "nexp = 11 min = -max\n", "smallest_normal = 2.2250738585072014e-308 smallest_subnormal = 4.9406564584124654e-324\n", "---------------------------------------------------------------\n", "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/54/g8szz35x7fs374vqm_k5_fc40000gn/T/ipykernel_2926/686629912.py:20: RuntimeWarning: overflow encountered in scalar multiply\n", " a = a*float_type(2.0)\n" ] } ], "source": [ "for ft in [float,np.float16,np.float32,np.float64,np.longdouble]:\n", " print(str(ft))\n", " check_underflow_limit(ft)\n", " check_overflow_limit(ft)\n", " check_machine_precision(ft)\n", " print('---------------')\n", " #Compare with numpy results\n", " print(np.finfo(ft))" ] }, { "cell_type": "code", "execution_count": null, "id": "fa938e53", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.1" } }, "nbformat": 4, "nbformat_minor": 5 }