intro-to-python/05_numbers_00_lecture.ipynb

8041 lines
322 KiB
Text

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"A **video presentation** of the contents in this chapter is shown below. A playlist with *all* chapters as videos is linked [here](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChALCAgOCggIDRYNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxgVERUWFxcYExMYGBgVFRgWFRYWGBcVGxIaEhMXFRoYGBISFRcVFRUVFRUVFRUVGBUSFxIVFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAgIDAQEAAAAAAAAAAAAABgcFCAIDBAEJ/8QAURAAAQQBAgMBCQgRAgUEAgMAAQACAwQRBRIGEyExBxQYIjJBVZTVCBUXUVJhk9QjMzVCU1RxcnN0dYGSsbKz05G0FiQ2YrU0gqGiY3YlQ0X/xAAcAQEAAgMBAQEAAAAAAAAAAAAAAgQBAwUHBgj/xAA9EQABAwIDBQUGBAYBBQEAAAABAAIRAyEEEjEFQVFhcRMVU4GRBiIyocHwFjRysRQ1QlLR4fEjM0NigpL/2gAMAwEAAhEDEQA/ANMkREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXF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hodQ0EBkkco21dQ8qJ4e0HOodmWhZBgrB0X6DItAPDV4q9H8P+q6j7RTw1eKvR/D/quo+0VhZW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/682q/aJ/0Mn9DloT4avFXo/h/1XUfaK4WPdo8UvY9hoaBh7XNOKuo5w4EHGdR7eqItaURERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERf/2Q==\n",
"text/html": [
"\n",
" <iframe\n",
" width=\"60%\"\n",
" height=\"300\"\n",
" src=\"https://www.youtube.com/embed/nB00WGCnVjg\"\n",
" frameborder=\"0\"\n",
" allowfullscreen\n",
" ></iframe>\n",
" "
],
"text/plain": [
"<IPython.lib.display.YouTubeVideo at 0x7f4b21935410>"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.display import YouTubeVideo\n",
"YouTubeVideo(\"nB00WGCnVjg\", width=\"60%\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Chapter 5: Numbers & Bits"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"After learning about the basic building blocks of expressing and structuring the business logic in programs, we focus our attention on the **data types** Python offers us, both built-in and available via the [standard library](https://docs.python.org/3/library/index.html) or third-party packages.\n",
"\n",
"We start with the \"simple\" ones: Numeric types in this chapter and textual data in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb). An important fact that holds for all objects of these types is that they are **immutable**. To reuse the bag analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Objects-vs.-Types-vs.-Values), this means that the $0$s and $1$s making up an object's *value* cannot be changed once the bag is created in memory, implying that any operation with or method on the object creates a *new* object in a *different* memory location.\n",
"\n",
"[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb), [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_lecture.ipynb), and [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_lecture.ipynb) then cover the more \"complex\" data types, including, for example, the `list` type. Finally, Chapter 10 completes the picture by introducing language constructs to create custom types.\n",
"\n",
"We have already seen many hints indicating that numbers are not as trivial to work with as it seems at first sight:\n",
"\n",
"- [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#%28Data%29-Type-%2F-%22Behavior%22) reveals that numbers may come in *different* data types (i.e., `int` vs. `float` so far),\n",
"- [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb#Boolean-Expressions) raises questions regarding the **limited precision** of `float` numbers (e.g., `42 == 42.000000000000001` evaluates to `True`), and\n",
"- [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Infinite-Recursion) shows that sometimes a `float` \"walks\" and \"quacks\" like an `int`, whereas the reverse is true.\n",
"\n",
"This chapter introduces all the [built-in numeric types](https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex): `int`, `float`, and `complex`. To mitigate the limited precision of floating-point numbers, we also look at two replacements for the `float` type in the [standard library](https://docs.python.org/3/library/index.html), namely the `Decimal` type in the [decimals](https://docs.python.org/3/library/decimal.html#decimal.Decimal) and the `Fraction` type in the [fractions](https://docs.python.org/3/library/fractions.html#fractions.Fraction) module."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## The `int` Type"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The simplest numeric type is the `int` type: It behaves like an [integer in ordinary math](https://en.wikipedia.org/wiki/Integer) (i.e., the set $\\mathbb{Z}$) and supports operators in the way we saw in the section on arithmetic operators in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#%28Arithmetic%29-Operators).\n",
"\n",
"One way to create `int` objects is by simply writing its value as a literal with the digits `0` to `9`."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"a = 42"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Just like any other object, the `42` has an identity, a type, and a value."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"94381541328960"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"id(a)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"int"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(a)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"A nice feature in newer Python versions is using underscores `_` as (thousands) separators in numeric literals. For example, `1_000_000` evaluates to `1000000` in memory; the `_` is ignored by the interpreter."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1000000"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1_000_000"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"We may place the `_`s anywhere we want."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"123456789"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1_2_3_4_5_6_7_8_9"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"It is syntactically invalid to write out leading `0` in numeric literals. The reason for that will become apparent in the next section."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "SyntaxError",
"evalue": "invalid token (<ipython-input-8-9a7f0f99e867>, line 1)",
"output_type": "error",
"traceback": [
"\u001b[0;36m File \u001b[0;32m\"<ipython-input-8-9a7f0f99e867>\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 042\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid token\n"
]
}
],
"source": [
"042"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Another way to create `int` objects is with the [int()](https://docs.python.org/3/library/functions.html#int) built-in that casts `float` or properly formatted `str` objects as integers. So, decimals are truncated (i.e., \"cut off\")."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"int(42.11)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"int(42.87)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Whereas the floor division operator `//` effectively rounds towards negative infinity (cf., the \"*(Arithmetic) Operators*\" section in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#%28Arithmetic%29-Operators)), the [int()](https://docs.python.org/3/library/functions.html#int) built-in effectively rounds towards `0`."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"-42"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"int(-42.87)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"When casting `str` objects as `int`, the [int()](https://docs.python.org/3/library/functions.html#int) built-in is less forgiving. We must not include any decimals as shows by the `ValueError`. Yet, leading and trailing whitespace is gracefully ignored."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"int(\"42\")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"ename": "ValueError",
"evalue": "invalid literal for int() with base 10: '42.0'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-13-faae6b054331>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"42.0\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: '42.0'"
]
}
],
"source": [
"int(\"42.0\")"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"int(\" 42 \")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The `int` type follows all rules we know from math, apart from one exception: Whereas mathematicians to this day argue what the term $0^0$ means (cf., this [article](https://en.wikipedia.org/wiki/Zero_to_the_power_of_zero)), programmers are pragmatic about this and simply define $0^0 = 1$."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0 ** 0"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Binary Representations"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"As computers can only store $0$s and $1$s, `int` objects are nothing but that in memory as well. Consequently, computer scientists and engineers developed conventions as to how $0$s and $1$s are \"translated\" into integers, and one such convention is the **[binary representation](https://en.wikipedia.org/wiki/Binary_number)** of **non-negative integers**. Consider the integers from $0$ through $255$ that are encoded into $0$s and $1$s with the help of this table:"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"|Bit $i$| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |\n",
"|-------|-----|-----|-----|-----|-----|-----|-----|-----|\n",
"| Digit |$2^7$|$2^6$|$2^5$|$2^4$|$2^3$|$2^2$|$2^1$|$2^0$|\n",
"| $=$ |$128$| $64$| $32$| $16$| $8$ | $4$ | $2$ | $1$ |"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"A number consists of exactly eight $0$s and $1$s that are read from right to left and referred to as the **bits** of the number. Each bit represents a distinct multiple of $2$, the **digit**. For sure, we start counting at $0$ again.\n",
"\n",
"To encode the integer $3$, for example, we need to find a combination of $0$s and $1$s such that the sum of digits marked with a $1$ is equal to the number we want to encode. In the example, we set all bits to $0$ except for the first ($i=0$) and second ($i=1$) as $2^0 + 2^1 = 1 + 2 = 3$. So the binary representation of $3$ is $00~00~00~11$. To borrow some terminology from linear algebra, the $3$ is a linear combination of the digits where the coefficients are either $0$ or $1$: $3 = 0*128 + 0*64 + 0*32 + 0*16 + 0*8 + 0*4 + 1*2 + 1*1$. It is *guaranteed* that there is exactly *one* such combination for each number between $0$ and $255$.\n",
"\n",
"As each bit in the binary representation is one of two values, we say that this representation has a base of $2$. Often, the base is indicated with a subscript to avoid confusion. For example, we write $3_{10} = 00000011_2$ or $3_{10} = 11_2$ for short omitting leading $0$s. A subscript of $10$ implies a decimal number as we know it from elementary school.\n",
"\n",
"We use the built-in [bin()](https://docs.python.org/3/library/functions.html#bin) function to obtain an `int` object's binary representation: It returns a `str` object starting with `\"0b\"` indicating the binary format and as many $0$s and $1$s as are necessary to encode the integer omitting leading $0$s."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b11'"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(3)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"We may pass a `str` object formatted this way as the argument to the [int()](https://docs.python.org/3/library/functions.html#int) built-in, together with `base=2`, to create an `int` object, for example, with the value of `3`."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"int(\"0b11\", base=2)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Moreover, we may also use the contents of the returned `str` object as a **literal** instead: Just like we type, for example, `3` without quotes (i.e., \"literally\") into a code cell to create the `int` object `3`, we may type `0b11` to obtain an `int` object with the same value."
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0b11"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Another example is the integer `123` that is the sum of $64 + 32 + 16 + 8 + 2 + 1$: Thus, its binary representation is the sequence of bits $01~11~10~11$, or to use our new notation, $123_{10} = 1111011_2$."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1111011'"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(123)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Analogous to typing `123` into a code cell, we may write `0b1111011`, or `0b_111_1011` to make use of the underscores, and create an `int` object with the value `123`."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"123"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0b_111_1011"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`0` and `255` are the edge cases where we set all the bits to either $0$ or $1$."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b0'"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(0)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1'"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(1)"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b10'"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(2)"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b11111111'"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(255)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Groups of eight bits are also called a **byte**. As a byte can only represent non-negative integers up to $255$, the table above is extended conceptually with greater digits to the left to model integers beyond $255$. The memory management needed to implement this is built into Python, and we do not need to worry about it.\n",
"\n",
"For example, `789` is encoded with ten bits and $789_{10} = 1100010101_2$."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1100010101'"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(789)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"To contrast this bits encoding with the familiar decimal system, we show an equivalent table with powers of $10$ as the digits:\n",
"\n",
"|Decimal| 3 | 2 | 1 | 0 |\n",
"|-------|------|------|------|------|\n",
"| Digit |$10^3$|$10^2$|$10^1$|$10^0$|\n",
"| $=$ |$1000$| $100$| $10$ | $1$ |\n",
"\n",
"Now, an integer is a linear combination of the digits where the coefficients are one of *ten* values, and the base is now $10$. For example, the number $123$ can be expressed as $0*1000 + 1*100 + 2*10 + 3*1$. So, the binary representation follows the same logic as the decimal system taught in elementary school. The decimal system is intuitive to us humans, mostly as we learn to count with our *ten* fingers. The $0$s and $1$s in a computer's memory are therefore no rocket science; they only feel unintuitive for a beginner."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Arithmetic with Bits"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Adding two numbers in their binary representations is straightforward and works just like we all learned addition in elementary school. Going from right to left, we add the individual digits, and ..."
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1 + 2"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1 + 0b10 = 0b11'"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(1) + \" + \" + bin(2) + \" = \" + bin(3)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"... if any two digits add up to $2$, the resulting digit is $0$ and a $1$ carries over."
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"4"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1 + 3"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1 + 0b11 = 0b100'"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(1) + \" + \" + bin(3) + \" = \" + bin(4)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Multiplication is also quite easy. All we need to do is to multiply the left operand by all digits of the right operand separately and then add up the individual products, just like in elementary school."
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"12"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"4 * 3"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b100 * 0b11 = 0b1100'"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(4) + \" * \" + bin(3) + \" = \" + bin(12)"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b100 * 0b1 = 0b100'"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(4) + \" * \" + bin(1) + \" = \" + bin(4) # multiply with first digit"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b100 * 0b10 = 0b1000'"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(4) + \" * \" + bin(2) + \" = \" + bin(8) # multiply with second digit"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The \"*Further Resources*\" section at the end of this chapter provides video tutorials on addition and multiplication in binary. Subtraction and division are a bit more involved but essentially also easy to understand."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Hexadecimal Representations"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"While in the binary and decimal systems there are two and ten distinct coefficients per digit, another convenient representation, the **hexadecimal representation**, uses a base of $16$. It is convenient as one digit stores the same amount of information as *four* bits and the binary representation quickly becomes unreadable for larger numbers. The letters \"a\" through \"f\" are used as digits \"10\" through \"15\".\n",
"\n",
"The following table summarizes the relationship between the three systems:"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"|Decimal|Hexadecimal|Binary|$~~~~~~$|Decimal|Hexadecimal|Binary|$~~~~~~$|Decimal|Hexadecimal|Binary|$~~~~~~$|...|\n",
"|-------|-----------|------|--------|-------|-----------|------|--------|-------|-----------|------|--------|---|\n",
"| 0 | 0 | 0000 |$~~~~~~$| 16 | 10 | 10000|$~~~~~~$| 32 | 20 |100000|$~~~~~~$|...|\n",
"| 1 | 1 | 0001 |$~~~~~~$| 17 | 11 | 10001|$~~~~~~$| 33 | 21 |100001|$~~~~~~$|...|\n",
"| 2 | 2 | 0010 |$~~~~~~$| 18 | 12 | 10010|$~~~~~~$| 34 | 22 |100010|$~~~~~~$|...|\n",
"| 3 | 3 | 0011 |$~~~~~~$| 19 | 13 | 10011|$~~~~~~$| 35 | 23 |100011|$~~~~~~$|...|\n",
"| 4 | 4 | 0100 |$~~~~~~$| 20 | 14 | 10100|$~~~~~~$| 36 | 24 |100100|$~~~~~~$|...|\n",
"| 5 | 5 | 0101 |$~~~~~~$| 21 | 15 | 10101|$~~~~~~$| 37 | 25 |100101|$~~~~~~$|...|\n",
"| 6 | 6 | 0110 |$~~~~~~$| 22 | 16 | 10110|$~~~~~~$| 38 | 26 |100110|$~~~~~~$|...|\n",
"| 7 | 7 | 0111 |$~~~~~~$| 23 | 17 | 10111|$~~~~~~$| 39 | 27 |100111|$~~~~~~$|...|\n",
"| 8 | 8 | 1000 |$~~~~~~$| 24 | 18 | 11000|$~~~~~~$| 40 | 28 |101000|$~~~~~~$|...|\n",
"| 9 | 9 | 1001 |$~~~~~~$| 25 | 19 | 11001|$~~~~~~$| 41 | 29 |101001|$~~~~~~$|...|\n",
"| 10 | a | 1010 |$~~~~~~$| 26 | 1a | 11010|$~~~~~~$| 42 | 2a |101010|$~~~~~~$|...|\n",
"| 11 | b | 1011 |$~~~~~~$| 27 | 1b | 11011|$~~~~~~$| 43 | 2b |101011|$~~~~~~$|...|\n",
"| 12 | c | 1100 |$~~~~~~$| 28 | 1c | 11100|$~~~~~~$| 44 | 2c |101100|$~~~~~~$|...|\n",
"| 13 | d | 1101 |$~~~~~~$| 29 | 1d | 11101|$~~~~~~$| 45 | 2d |101101|$~~~~~~$|...|\n",
"| 14 | e | 1110 |$~~~~~~$| 30 | 1e | 11110|$~~~~~~$| 46 | 2e |101110|$~~~~~~$|...|\n",
"| 15 | f | 1111 |$~~~~~~$| 31 | 1f | 11111|$~~~~~~$| 47 | 2f |101111|$~~~~~~$|...|"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"To show more examples of the above subscript convention, we pick three random entries from the table:\n",
"\n",
"$11_{10} = \\text{b}_{16} = 1011_2$\n",
"\n",
"$25_{10} = 19_{16} = 11001_2$\n",
"\n",
"$46_{10} = 2\\text{e}_{16} = 101110_2$\n",
"\n",
"The built-in [hex()](https://docs.python.org/3/library/functions.html#hex) function creates a `str` object starting with `\"0x\"` representing an `int` object's hexadecimal representation. The length depends on how many groups of four bits are implied by the corresponding binary representation.\n",
"\n",
"For `0` and `1`, the hexadecimal representation is similar to the binary one."
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x0'"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(0)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x1'"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(1)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Whereas `bin(3)` already requires two digits, one is enough for `hex(3)`."
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x3'"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(3) # bin(3) => \"0b11\"; two digits needed"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"For `10` and `15`, we see the letter digits for the first time."
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0xa'"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(10)"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0xf'"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(15)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The binary representation of `123`, `0b_111_1011`, can be viewed as *two* groups of four bits, $0111$ and $1011$, that are encoded as $7$ and $\\text{b}$ in hexadecimal (cf., table above)."
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1111011'"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(123)"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x7b'"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(123)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"To obtain a *new* `int` object with the value `123`, we call the [int()](https://docs.python.org/3/library/functions.html#int) built-in with a properly formatted `str` object and `base=16` as arguments."
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"123"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"int(\"0x7b\", base=16)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Alternatively, we could use a literal notation instead."
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"123"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0x7b"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Hexadecimals between $00_{16}$ and $\\text{ff}_{16}$ (i.e., $0_{10}$ and $255_{10}$) are commonly used to describe colors, for example, in web development but also graphics editors. See this [online tool](https://www.w3schools.com/colors/colors_hexadecimal.asp) for some more background."
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x0'"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(0)"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0xff'"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(255)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Just like binary representations, the hexadecimals extend to the left for larger numbers like `789`."
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x315'"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(789)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"For completeness sake, we mention that there is also the [oct()](https://docs.python.org/3/library/functions.html#oct) built-in to obtain an integer's **octal representation**. The logic is the same as for the hexadecimal representation, and we use *eight* instead of *sixteen* digits. That is the equivalent of viewing the binary representations in groups of three bits. As of today, octal representations have become less important, and the data science practitioner may probably live without them quite well."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"### Negative Values"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"While there are conventions that model negative integers with $0$s and $1$s in memory (cf., [Two's Complement](https://en.wikipedia.org/wiki/Two%27s_complement)), Python manages that for us, and we do not look into the theory here for brevity. We have learned all that a practitioner needs to know about how integers are modeled in a computer. The \"*Further Resources*\" section at the end of this chapter provides a video tutorial on how the [Two's Complement](https://en.wikipedia.org/wiki/Two%27s_complement) idea works.\n",
"\n",
"The binary and hexadecimal representations of negative integers are identical to their positive counterparts except that they start with a minus sign `-`. However, as the video tutorial at the end of the chapter reveals, that is *not* how the bits are organized in memory."
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'-0b11'"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(-3)"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'-0x3'"
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(-3)"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'-0b11111111'"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(-255)"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'-0xff'"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(-255)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### The `bool` Type"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Whereas the boolean literals `True` and `False` are commonly *not* regarded as numeric types, they behave like `1` and `0` in an arithmetic context."
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"True + False"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"41 + True"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0.0"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"42.87 * False"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"We may explicitly cast `bool` objects as integers ourselves with the [int()](https://docs.python.org/3/library/functions.html#int) built-in."
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"int(True)"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"int(False)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Of course, their binary representations only need *one* bit of information."
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1'"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(True)"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b0'"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(False)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Their hexadecimal representations occupy *four* bits in memory while only *one* bit is needed. This is because \"1\" and \"0\" are just two of the sixteen possible digits."
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x1'"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(True)"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x0'"
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"hex(False)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"As a reminder, the `None` object is a type on its own, namely the `NoneType`, and different from `False`. It *cannot* be cast as an integer as the `TypeError` indicates."
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "TypeError",
"evalue": "int() argument must be a string, a bytes-like object or a number, not 'NoneType'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-59-af2123a46eb2>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m: int() argument must be a string, a bytes-like object or a number, not 'NoneType'"
]
}
],
"source": [
"int(None)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Bitwise Operators"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Now that we know how integers are represented with $0$s and $1$s, we look at ways of working with the individual bits, in particular with the so-called **[bitwise operators](https://wiki.python.org/moin/BitwiseOperators)**: As the name suggests, the operators perform some operation on a bit by bit basis. They only work with and always return `int` objects.\n",
"\n",
"We keep this overview rather short as such \"low-level\" operations are not needed by the data science practitioner regularly. Yet, it is worthwhile to have heard about them as they form the basis of all of arithmetic in computers.\n",
"\n",
"The first operator is the **bitwise AND** operator `&`: It looks at the bits of its two operands, `11` and `13` in the example, in a pairwise fashion and if *both* operands have a $1$ in the *same* position, the resulting integer will have a $1$ in this position as well. Otherwise, the resulting integer will have a $0$ in this position. The binary representations of `11` and `13` both have $1$s in their respective first and fourth bits, which is why `bin(11 & 13)` evaluates to `Ob_1001` or `9`."
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"9"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"11 & 13"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1011 & 0b1101'"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(11) + \" & \" + bin(13) # to show the operands' bits"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1001'"
]
},
"execution_count": 62,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(11 & 13)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`0b_1001` is the binary representation of `9`."
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"9"
]
},
"execution_count": 63,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0b_1001"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The **bitwise OR** operator `|` evaluates to an `int` object whose bits are set to $1$ if the corresponding bits of either *one* or *both* operands are $1$. So in the example `9 | 13` only the second bit is $0$ for both operands, which is why the expression evaluates to `0b_1101` or `13`."
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"13"
]
},
"execution_count": 64,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"9 | 13"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1001 | 0b1101'"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(9) + \" | \" + bin(13) # to show the operands' bits"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1101'"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(9 | 13)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`0b_1101` evaluates to an `int` object with the value `13`."
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"13"
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0b_1101"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The **bitwise XOR** operator `^` is a special case of the `|` operator in that it evaluates to an `int` object whose bits are set to $1$ if the corresponding bit of *exactly one* of the two operands is $1$. Colloquially, the \"X\" stands for \"exclusive.\" The `^` operator must *not* be confused with the exponentiation operator `**`! In the example, `9 ^ 13`, only the third bit differs between the two operands, which is why it evaluates to `0b_100` omitting the leading $0$."
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"4"
]
},
"execution_count": 68,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"9 ^ 13"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b1001 ^ 0b1101'"
]
},
"execution_count": 69,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(9) + \" ^ \" + bin(13) # to show the operands' bits"
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b100'"
]
},
"execution_count": 70,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(9 ^ 13)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`0b_100` evaluates to an `int` object with the value `4`."
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"4"
]
},
"execution_count": 71,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0b_100"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The **bitwise NOT** operator `~`, sometimes also called **inversion** operator, is said to \"flip\" the $0$s into $1$s and the $1$s into $0$s. However, it is based on the aforementioned [Two's Complement](https://en.wikipedia.org/wiki/Two%27s_complement) convention and `~x = -(x + 1)` by definition (cf., the [reference](https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations)). The full logic behind this, while actually quite simple, is considered out of scope in this book.\n",
"\n",
"We can at least verify the definition by comparing the binary representations of `7` and `-8`: They are indeed the same."
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"-8"
]
},
"execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"~7"
]
},
{
"cell_type": "code",
"execution_count": 73,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 73,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"~7 == -(7 + 1) # = Two's Complement"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'-0b1000'"
]
},
"execution_count": 74,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(~7)"
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'-0b1000'"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(-(7 + 1))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`~x = -(x + 1)` can be reformulated as `~x + x = -1`, which is slightly easier to check."
]
},
{
"cell_type": "code",
"execution_count": 76,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"-1"
]
},
"execution_count": 76,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"~7 + 7"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Lastly, the **bitwise left and right shift** operators, `<<` and `>>`, shift all the bits either to the left or to the right. This corresponds to multiplying or dividing an integer by powers of `2`.\n",
"\n",
"When shifting left, $0$s are filled in."
]
},
{
"cell_type": "code",
"execution_count": 77,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"28"
]
},
"execution_count": 77,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"7 << 2"
]
},
{
"cell_type": "code",
"execution_count": 78,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b111'"
]
},
"execution_count": 78,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(7)"
]
},
{
"cell_type": "code",
"execution_count": 79,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b11100'"
]
},
"execution_count": 79,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(7 << 2)"
]
},
{
"cell_type": "code",
"execution_count": 80,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"28"
]
},
"execution_count": 80,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0b_1_1100"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"When shifting right, some bits are always lost."
]
},
{
"cell_type": "code",
"execution_count": 81,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 81,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"7 >> 1"
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b111'"
]
},
"execution_count": 82,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(7)"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0b11'"
]
},
"execution_count": 83,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bin(7 >> 1)"
]
},
{
"cell_type": "code",
"execution_count": 84,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 84,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0b_11"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## The `float` Type"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"As we have seen above, some assumptions need to be made as to how the $0$s and $1$s in a computer's memory are to be translated into numbers. This process becomes a lot more involved when we go beyond integers and model [real numbers](https://en.wikipedia.org/wiki/Real_number) (i.e., the set $\\mathbb{R}$) with possibly infinitely many digits to the right of the period like $1.23$.\n",
"\n",
"The **[Institute of Electrical and Electronics Engineers](https://en.wikipedia.org/wiki/Institute_of_Electrical_and_Electronics_Engineers)** (IEEE, pronounced \"eye-triple-E\") is one of the important professional associations when it comes to standardizing all kinds of aspects regarding the implementation of soft- and hardware.\n",
"\n",
"The **[IEEE 754](https://en.wikipedia.org/wiki/IEEE_754)** standard defines the so-called **floating-point arithmetic** that is commonly used today by all major programming languages. The standard not only defines how the $0$s and $1$s are organized in memory but also, for example, how values are to be rounded, what happens in exceptional cases like divisions by zero, or what is a zero value in the first place.\n",
"\n",
"In Python, the simplest way to create a `float` object is to use a literal notation with a dot `.` in it."
]
},
{
"cell_type": "code",
"execution_count": 85,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"b = 42.0"
]
},
{
"cell_type": "code",
"execution_count": 86,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"139960518791696"
]
},
"execution_count": 86,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"id(b)"
]
},
{
"cell_type": "code",
"execution_count": 87,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"float"
]
},
"execution_count": 87,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(b)"
]
},
{
"cell_type": "code",
"execution_count": 88,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42.0"
]
},
"execution_count": 88,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"As with integer literals above, we may use underscores `_` to make longer `float` objects easier to read."
]
},
{
"cell_type": "code",
"execution_count": 89,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0.123456789"
]
},
"execution_count": 89,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0.123_456_789"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"In cases where the dot `.` is unnecessary from a mathematical point of view, we either need to end the number with it nevertheless or use the [float()](https://docs.python.org/3/library/functions.html#float) built-in to cast the number explicitly. [float()](https://docs.python.org/3/library/functions.html#float) can process any numeric object or a properly formatted `str` object."
]
},
{
"cell_type": "code",
"execution_count": 90,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42.0"
]
},
"execution_count": 90,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"42."
]
},
{
"cell_type": "code",
"execution_count": 91,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42.0"
]
},
"execution_count": 91,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(42)"
]
},
{
"cell_type": "code",
"execution_count": 92,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42.0"
]
},
"execution_count": 92,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"42\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Leading and trailing whitespace is ignored ..."
]
},
{
"cell_type": "code",
"execution_count": 93,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42.87"
]
},
"execution_count": 93,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\" 42.87 \")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"... but not whitespace in between."
]
},
{
"cell_type": "code",
"execution_count": 94,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"ename": "ValueError",
"evalue": "could not convert string to float: '42. 87'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-94-c7953b8b7956>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfloat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"42. 87\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mValueError\u001b[0m: could not convert string to float: '42. 87'"
]
}
],
"source": [
"float(\"42. 87\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`float` objects are implicitly created as the result of dividing an `int` object by another with the division operator `/`."
]
},
{
"cell_type": "code",
"execution_count": 95,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0.3333333333333333"
]
},
"execution_count": 95,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1 / 3"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"In general, if we combine `float` and `int` objects in arithmetic operations, we always end up with a `float` type: Python uses the \"broader\" representation."
]
},
{
"cell_type": "code",
"execution_count": 96,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42.0"
]
},
"execution_count": 96,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"40.0 + 2"
]
},
{
"cell_type": "code",
"execution_count": 97,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42.0"
]
},
"execution_count": 97,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"21 * 2.0"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Scientific Notation"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`float` objects may also be created with the **scientific literal notation**: We use the symbol `e` to indicate powers of $10$, so $1.23 * 10^0$ translates into `1.23e0`."
]
},
{
"cell_type": "code",
"execution_count": 98,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1.23"
]
},
"execution_count": 98,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1.23e0"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Syntactically, `e` needs a `float` or `int` object in its literal notation on its left and an `int` object on its right, both without a space. Otherwise, we get a `SyntaxError`."
]
},
{
"cell_type": "code",
"execution_count": 99,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"ename": "SyntaxError",
"evalue": "invalid syntax (<ipython-input-99-1b5daaac0077>, line 1)",
"output_type": "error",
"traceback": [
"\u001b[0;36m File \u001b[0;32m\"<ipython-input-99-1b5daaac0077>\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 1.23 e0\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
]
}
],
"source": [
"1.23 e0"
]
},
{
"cell_type": "code",
"execution_count": 100,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"ename": "SyntaxError",
"evalue": "invalid syntax (<ipython-input-100-a236c4a30231>, line 1)",
"output_type": "error",
"traceback": [
"\u001b[0;36m File \u001b[0;32m\"<ipython-input-100-a236c4a30231>\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 1.23e 0\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
]
}
],
"source": [
"1.23e 0"
]
},
{
"cell_type": "code",
"execution_count": 101,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"ename": "SyntaxError",
"evalue": "invalid syntax (<ipython-input-101-05b9072d76be>, line 1)",
"output_type": "error",
"traceback": [
"\u001b[0;36m File \u001b[0;32m\"<ipython-input-101-05b9072d76be>\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 1.23e0.0\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
]
}
],
"source": [
"1.23e0.0"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"If we leave out the number to the left, Python raises a `NameError` as it unsuccessfully tries to look up a variable named `e0`."
]
},
{
"cell_type": "code",
"execution_count": 102,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'e0' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-102-abc4de6ccb5e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0me0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mNameError\u001b[0m: name 'e0' is not defined"
]
}
],
"source": [
"e0"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"So, to write $10^0$ in Python, we need to think of it as $1*10^0$ and write `1e0`."
]
},
{
"cell_type": "code",
"execution_count": 103,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1.0"
]
},
"execution_count": 103,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1e0"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"To express thousands of something (i.e., $10^3$), we write `1e3`."
]
},
{
"cell_type": "code",
"execution_count": 104,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1000.0"
]
},
"execution_count": 104,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1e3 # = thousands"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Similarly, to express, for example, milliseconds (i.e., $10^{-3} s$), we write `1e-3`."
]
},
{
"cell_type": "code",
"execution_count": 105,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0.001"
]
},
"execution_count": 105,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1e-3 # = milli"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Special Values"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"There are also three special values representing \"**not a number,**\" called `nan`, and positive or negative **infinity**, called `inf` or `-inf`, that are created by passing in the corresponding abbreviation as a `str` object to the [float()](https://docs.python.org/3/library/functions.html#float) built-in. These values could be used, for example, as the result of a mathematically undefined operation like division by zero or to model the value of a mathematical function as it goes to infinity."
]
},
{
"cell_type": "code",
"execution_count": 106,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"nan"
]
},
"execution_count": 106,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"nan\") # also float(\"NaN\")"
]
},
{
"cell_type": "code",
"execution_count": 107,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"inf"
]
},
"execution_count": 107,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"+inf\") # also float(\"+infinity\") or float(\"infinity\")"
]
},
{
"cell_type": "code",
"execution_count": 108,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"inf"
]
},
"execution_count": 108,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"inf\") # also float(\"+inf\")"
]
},
{
"cell_type": "code",
"execution_count": 109,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"-inf"
]
},
"execution_count": 109,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"-inf\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`nan` objects *never* compare equal to *anything*, not even to themselves. This happens in accordance with the [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) standard."
]
},
{
"cell_type": "code",
"execution_count": 110,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 110,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"nan\") == float(\"nan\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Another caveat is that any arithmetic involving a `nan` object results in `nan`. In other words, the addition below **fails silently** as no error is raised. As this also happens in accordance with the [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) standard, we *need* to be aware of that and check any data we work with for any `nan` occurrences *before* doing any calculations."
]
},
{
"cell_type": "code",
"execution_count": 111,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"nan"
]
},
"execution_count": 111,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"42 + float(\"nan\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"On the contrary, as two values go to infinity, there is no such concept as difference and *everything* compares equal."
]
},
{
"cell_type": "code",
"execution_count": 112,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 112,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"inf\") == float(\"inf\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Adding `42` to `inf` makes no difference."
]
},
{
"cell_type": "code",
"execution_count": 113,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"inf"
]
},
"execution_count": 113,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"inf\") + 42"
]
},
{
"cell_type": "code",
"execution_count": 114,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 114,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"inf\") + 42 == float(\"inf\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"We observe the same for multiplication ..."
]
},
{
"cell_type": "code",
"execution_count": 115,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"inf"
]
},
"execution_count": 115,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"42 * float(\"inf\")"
]
},
{
"cell_type": "code",
"execution_count": 116,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 116,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"42 * float(\"inf\") == float(\"inf\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"... and even exponentiation!"
]
},
{
"cell_type": "code",
"execution_count": 117,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"inf"
]
},
"execution_count": 117,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"inf\") ** 42"
]
},
{
"cell_type": "code",
"execution_count": 118,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 118,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"inf\") ** 42 == float(\"inf\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Although absolute differences become unmeaningful as we approach infinity, signs are still respected."
]
},
{
"cell_type": "code",
"execution_count": 119,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"inf"
]
},
"execution_count": 119,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"-42 * float(\"-inf\")"
]
},
{
"cell_type": "code",
"execution_count": 120,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 120,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"-42 * float(\"-inf\") == float(\"inf\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"As a caveat, adding infinities of different signs is an *undefined operation* in math and results in a `nan` object. So, if we (accidentally or unknowingly) do this on a real dataset, we do *not* see any error messages, and our program may continue to run with non-meaningful results! This is another example of a piece of code **failing silently**."
]
},
{
"cell_type": "code",
"execution_count": 121,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"nan"
]
},
"execution_count": 121,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"inf\") + float(\"-inf\")"
]
},
{
"cell_type": "code",
"execution_count": 122,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"nan"
]
},
"execution_count": 122,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"float(\"inf\") - float(\"inf\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Imprecision"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`float` objects are *inherently* imprecise, and there is *nothing* we can do about it! In particular, arithmetic operations with two `float` objects may result in \"weird\" rounding \"errors\" that are strictly deterministic and occur in accordance with the [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) standard.\n",
"\n",
"For example, let's add `1` to `1e15` and `1e16`, respectively. In the latter case, the `1` somehow gets \"lost.\""
]
},
{
"cell_type": "code",
"execution_count": 123,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1000000000000001.0"
]
},
"execution_count": 123,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1e15 + 1"
]
},
{
"cell_type": "code",
"execution_count": 124,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1e+16"
]
},
"execution_count": 124,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1e16 + 1"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Interactions between sufficiently large and small `float` objects are not the only source of imprecision."
]
},
{
"cell_type": "code",
"execution_count": 125,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"from math import sqrt"
]
},
{
"cell_type": "code",
"execution_count": 126,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"2.0000000000000004"
]
},
"execution_count": 126,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sqrt(2) ** 2"
]
},
{
"cell_type": "code",
"execution_count": 127,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0.30000000000000004"
]
},
"execution_count": 127,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0.1 + 0.2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"This may become a problem if we rely on equality checks in our programs."
]
},
{
"cell_type": "code",
"execution_count": 128,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 128,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sqrt(2) ** 2 == 2"
]
},
{
"cell_type": "code",
"execution_count": 129,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 129,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0.1 + 0.2 == 0.3"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"A popular workaround is to benchmark the absolute value of the difference between the two numbers to be checked for equality against a pre-defined `threshold` *sufficiently* close to `0`, for example, `1e-15`."
]
},
{
"cell_type": "code",
"execution_count": 130,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"threshold = 1e-15"
]
},
{
"cell_type": "code",
"execution_count": 131,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 131,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"abs((sqrt(2) ** 2) - 2) < threshold"
]
},
{
"cell_type": "code",
"execution_count": 132,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 132,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"abs((0.1 + 0.2) - 0.3) < threshold"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The built-in [format()](https://docs.python.org/3/library/functions.html#format) function allows us to show the **significant digits** of a `float` number as they exist in memory to arbitrary precision. To exemplify it, let's view a couple of `float` objects with `50` digits. This analysis reveals that almost no `float` number is precise! After 14 or 15 digits \"weird\" things happen. As we see further below, the \"random\" digits ending the `float` numbers do *not* \"physically\" exist in memory! Rather, they are \"calculated\" by the [format()](https://docs.python.org/3/library/functions.html#format) function that is forced to show `50` digits.\n",
"\n",
"The [format()](https://docs.python.org/3/library/functions.html#format) function is different from the [format()](https://docs.python.org/3/library/stdtypes.html#str.format) method on `str` objects introduced in the next chapter (cf., [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb#format%28%29-Method)): Yet, both work with the so-called [format specification mini-language](https://docs.python.org/3/library/string.html#format-specification-mini-language): `\".50f\"` is the instruction to show `50` digits of a `float` number."
]
},
{
"cell_type": "code",
"execution_count": 133,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0.10000000000000000555111512312578270211815834045410'"
]
},
"execution_count": 133,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"format(0.1, \".50f\")"
]
},
{
"cell_type": "code",
"execution_count": 134,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0.20000000000000001110223024625156540423631668090820'"
]
},
"execution_count": 134,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"format(0.2, \".50f\")"
]
},
{
"cell_type": "code",
"execution_count": 135,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0.29999999999999998889776975374843459576368331909180'"
]
},
"execution_count": 135,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"format(0.3, \".50f\")"
]
},
{
"cell_type": "code",
"execution_count": 136,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0.33333333333333331482961625624739099293947219848633'"
]
},
"execution_count": 136,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"format(1 / 3, \".50f\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The [format()](https://docs.python.org/3/library/functions.html#format) function does *not* round a `float` object in the mathematical sense! It just allows us to show an arbitrary number of the digits as stored in memory, and it also does *not* change these.\n",
"\n",
"On the contrary, the built-in [round()](https://docs.python.org/3/library/functions.html#round) function creates a *new* numeric object that is a rounded version of the one passed in as the argument. It adheres to the common rules of math.\n",
"\n",
"For example, let's round `1 / 3` to five decimals. The obtained value for `roughly_a_third` is also *imprecise* but different from the \"exact\" representation of `1 / 3` above."
]
},
{
"cell_type": "code",
"execution_count": 137,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"roughly_a_third = round(1 / 3, 5)"
]
},
{
"cell_type": "code",
"execution_count": 138,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0.33333"
]
},
"execution_count": 138,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"roughly_a_third"
]
},
{
"cell_type": "code",
"execution_count": 139,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0.33333000000000001517008740847813896834850311279297'"
]
},
"execution_count": 139,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"format(roughly_a_third, \".50f\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Surprisingly, `0.125` and `0.25` appear to be *precise*, and equality comparison works without the `threshold` workaround: Both are powers of $2$ in disguise."
]
},
{
"cell_type": "code",
"execution_count": 140,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0.12500000000000000000000000000000000000000000000000'"
]
},
"execution_count": 140,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"format(0.125, \".50f\")"
]
},
{
"cell_type": "code",
"execution_count": 141,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0.25000000000000000000000000000000000000000000000000'"
]
},
"execution_count": 141,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"format(0.25, \".50f\")"
]
},
{
"cell_type": "code",
"execution_count": 142,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 142,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"0.125 + 0.125 == 0.25"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Binary Representations"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"To understand these subtleties, we need to look at the **[binary representation of floats](https://en.wikipedia.org/wiki/Double-precision_floating-point_format)** and review the basics of the **[IEEE 754](https://en.wikipedia.org/wiki/IEEE_754)** standard. On modern machines, floats are modeled in so-called double precision with $64$ bits that are grouped as in the figure below. The first bit determines the sign ($0$ for plus, $1$ for minus), the next $11$ bits represent an $exponent$ term, and the last $52$ bits resemble the actual significant digits, the so-called $fraction$ part. The three groups are put together like so:"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"$$float = (-1)^{sign} * 1.fraction * 2^{exponent-1023}$$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"A $1.$ is implicitly prepended as the first digit, and both, $fraction$ and $exponent$, are stored in base $2$ representation (i.e., they both are interpreted like integers above). As $exponent$ is consequently non-negative, between $0_{10}$ and $2047_{10}$ to be precise, the $-1023$, called the exponent bias, centers the entire $2^{exponent-1023}$ term around $1$ and allows the period within the $1.fraction$ part be shifted into either direction by the same amount. Floating-point numbers received their name as the period, formally called the **[radix point](https://en.wikipedia.org/wiki/Radix_point)**, \"floats\" along the significant digits. As an aside, an $exponent$ of all $0$s or all $1$s is used to model the special values `nan` or `inf`.\n",
"\n",
"As the standard defines the exponent part to come as a power of $2$, we now see why `0.125` is a *precise* float: It can be represented as a power of $2$, i.e., $0.125 = (-1)^0 * 1.0 * 2^{1020-1023} = 2^{-3} = \\frac{1}{8}$. In other words, the floating-point representation of $0.125_{10}$ is $0_2$, $1111111100_2 = 1020_{10}$, and $0_2$ for the three groups, respectively."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"<img src=\"static/floating_point.png\" width=\"85%\" align=\"center\">"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The crucial fact for the data science practitioner to understand is that mapping the *infinite* set of the real numbers $\\mathbb{R}$ to a *finite* set of bits leads to the imprecisions shown above!\n",
"\n",
"So, floats are usually good approximations of real numbers only with their first $14$ or $15$ digits. If more precision is required, we need to revert to other data types such as a `Decimal` or a `Fraction`, as shown in the next two sections.\n",
"\n",
"This [blog post](http://fabiensanglard.net/floating_point_visually_explained/) gives another neat and *visual* way as to how to think of floats. It also explains why floats become worse approximations of the reals as their absolute values increase.\n",
"\n",
"The Python [documentation](https://docs.python.org/3/tutorial/floatingpoint.html) provides another good discussion of floats and the goodness of their approximations.\n",
"\n",
"If we are interested in the exact bits behind a `float` object, we use the [hex()](https://docs.python.org/3/library/stdtypes.html#float.hex) method that returns a `str` object beginning with `\"0x1.\"` followed by the $fraction$ in hexadecimal notation and the $exponent$ as an integer after subtraction of $1023$ and separated by a `\"p\"`."
]
},
{
"cell_type": "code",
"execution_count": 143,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"one_eighth = 1 / 8"
]
},
{
"cell_type": "code",
"execution_count": 144,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x1.0000000000000p-3'"
]
},
"execution_count": 144,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"one_eighth.hex()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Also, the [as_integer_ratio()](https://docs.python.org/3/library/stdtypes.html#float.as_integer_ratio) method returns the two smallest integers whose ratio best approximates a `float` object."
]
},
{
"cell_type": "code",
"execution_count": 145,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(1, 8)"
]
},
"execution_count": 145,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"one_eighth.as_integer_ratio()"
]
},
{
"cell_type": "code",
"execution_count": 146,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x1.555475a31a4bep-2'"
]
},
"execution_count": 146,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"roughly_a_third.hex()"
]
},
{
"cell_type": "code",
"execution_count": 147,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(3002369727582815, 9007199254740992)"
]
},
"execution_count": 147,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"roughly_a_third.as_integer_ratio()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`0.0` is also a power of $2$ and thus a *precise* `float` number."
]
},
{
"cell_type": "code",
"execution_count": 148,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"zero = 0.0"
]
},
{
"cell_type": "code",
"execution_count": 149,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0x0.0p+0'"
]
},
"execution_count": 149,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"zero.hex()"
]
},
{
"cell_type": "code",
"execution_count": 150,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(0, 1)"
]
},
"execution_count": 150,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"zero.as_integer_ratio()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"As seen in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#%28Data%29-Type-%2F-%22Behavior%22), the [is_integer()](https://docs.python.org/3/library/stdtypes.html#float.is_integer) method tells us if a `float` can be casted as an `int` object without any loss in precision."
]
},
{
"cell_type": "code",
"execution_count": 151,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 151,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"roughly_a_third.is_integer()"
]
},
{
"cell_type": "code",
"execution_count": 152,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 152,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"one = roughly_a_third / roughly_a_third\n",
"\n",
"one.is_integer()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"As the exact implementation of floats may vary and be dependent on a particular Python installation, we look up the [float_info](https://docs.python.org/3/library/sys.html#sys.float_info) attribute in the [sys](https://docs.python.org/3/library/sys.html) module in the [standard library](https://docs.python.org/3/library/index.html) to check the details. Usually, this is not necessary."
]
},
{
"cell_type": "code",
"execution_count": 153,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"import sys"
]
},
{
"cell_type": "code",
"execution_count": 154,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)"
]
},
"execution_count": 154,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sys.float_info"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## The `Decimal` Type"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The [decimal](https://docs.python.org/3/library/decimal.html) module in the [standard library](https://docs.python.org/3/library/index.html) provides a [Decimal](https://docs.python.org/3/library/decimal.html#decimal.Decimal) type that may be used to represent any real number to a user-defined level of precision: \"User-defined\" does *not* mean an infinite or exact precision! The `Decimal` type merely allows us to work with a number of bits *different* from the $64$ as specified for the `float` type and also to customize the rounding rules and some other settings.\n",
"\n",
"We import the `Decimal` type and also the [getcontext()](https://docs.python.org/3/library/decimal.html#decimal.getcontext) function from the [decimal](https://docs.python.org/3/library/decimal.html) module."
]
},
{
"cell_type": "code",
"execution_count": 155,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"from decimal import Decimal, getcontext"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"[getcontext()](https://docs.python.org/3/library/decimal.html#decimal.getcontext) shows us how the [decimal](https://docs.python.org/3/library/decimal.html) module is set up. By default, the precision is set to `28` significant digits, which is roughly twice as many as with `float` objects."
]
},
{
"cell_type": "code",
"execution_count": 156,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])"
]
},
"execution_count": 156,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"getcontext()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The two simplest ways to create a `Decimal` object is to either **instantiate** it with an `int` or a `str` object consisting of all the significant digits. In the latter case, the scientific notation is also possible."
]
},
{
"cell_type": "code",
"execution_count": 157,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('42')"
]
},
"execution_count": 157,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(42)"
]
},
{
"cell_type": "code",
"execution_count": 158,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('0.1')"
]
},
"execution_count": 158,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"0.1\")"
]
},
{
"cell_type": "code",
"execution_count": 159,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('0.001')"
]
},
"execution_count": 159,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"1e-3\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"It is *not* a good idea to create a `Decimal` from a `float` object. If we did so, we would create a `Decimal` object that internally used extra bits to store the \"random\" digits that are not stored in the `float` object in the first place."
]
},
{
"cell_type": "code",
"execution_count": 160,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('0.1000000000000000055511151231257827021181583404541015625')"
]
},
"execution_count": 160,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(0.1) # do not do this!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"With the `Decimal` type, the imprecisions in the arithmetic and equality comparisons from above go away."
]
},
{
"cell_type": "code",
"execution_count": 161,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('0.3')"
]
},
"execution_count": 161,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"0.1\") + Decimal(\"0.2\")"
]
},
{
"cell_type": "code",
"execution_count": 162,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 162,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"0.1\") + Decimal(\"0.2\") == Decimal(\"0.3\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`Decimal` numbers *preserve* the **significant digits**, even in cases where this is not needed."
]
},
{
"cell_type": "code",
"execution_count": 163,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('0.30000')"
]
},
"execution_count": 163,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"0.10000\") + Decimal(\"0.20000\")"
]
},
{
"cell_type": "code",
"execution_count": 164,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 164,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"0.10000\") + Decimal(\"0.20000\") == Decimal(\"0.3\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Arithmetic operations between `Decimal` and `int` objects work as the latter are inherently precise: The results are *new* `Decimal` objects."
]
},
{
"cell_type": "code",
"execution_count": 165,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('42')"
]
},
"execution_count": 165,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"21 + Decimal(21)"
]
},
{
"cell_type": "code",
"execution_count": 166,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('42.0')"
]
},
"execution_count": 166,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"10 * Decimal(\"4.2\")"
]
},
{
"cell_type": "code",
"execution_count": 167,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('0.1')"
]
},
"execution_count": 167,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(1) / 10"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"To verify the precision, we apply the built-in [format()](https://docs.python.org/3/library/functions.html#format) function to the previous code cell and compare it with the same division resulting in a `float` object."
]
},
{
"cell_type": "code",
"execution_count": 168,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0.10000000000000000000000000000000000000000000000000'"
]
},
"execution_count": 168,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"format(Decimal(1) / 10, \".50f\")"
]
},
{
"cell_type": "code",
"execution_count": 169,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0.10000000000000000555111512312578270211815834045410'"
]
},
"execution_count": 169,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"format(1 / 10, \".50f\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"However, mixing `Decimal` and `float` objects raises a `TypeError`: So, Python prevents us from potentially introducing imprecisions via innocent-looking arithmetic by **failing loudly**."
]
},
{
"cell_type": "code",
"execution_count": 170,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "TypeError",
"evalue": "unsupported operand type(s) for *: 'float' and 'decimal.Decimal'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-170-a3cea145e6d1>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;36m1.0\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mDecimal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m42\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for *: 'float' and 'decimal.Decimal'"
]
}
],
"source": [
"1.0 * Decimal(42)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"To preserve the precision for more advanced mathematical functions, `Decimal` objects come with many **methods bound** on them. For example, [ln()](https://docs.python.org/3/library/decimal.html#decimal.Decimal.ln) and [log10()](https://docs.python.org/3/library/decimal.html#decimal.Decimal.log10) take the logarithm while [sqrt()](https://docs.python.org/3/library/decimal.html#decimal.Decimal.sqrt) calculates the square root. The methods always return a *new* `Decimal` object. We must never use the functions in the [math](https://docs.python.org/3/library/math.html) module in the [standard library](https://docs.python.org/3/library/index.html) with `Decimal` objects as they do *not* preserve precision."
]
},
{
"cell_type": "code",
"execution_count": 171,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('2')"
]
},
"execution_count": 171,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(100).log10()"
]
},
{
"cell_type": "code",
"execution_count": 172,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('1.414213562373095048801688724')"
]
},
"execution_count": 172,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(2).sqrt()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The object returned by the [sqrt()](https://docs.python.org/3/library/decimal.html#decimal.Decimal.sqrt) method is still limited in precision: This must be so as, for example, $\\sqrt{2}$ is an **[irrational number](https://en.wikipedia.org/wiki/Irrational_number)** that *cannot* be expressed with absolute precision using *any* number of bits, even in theory.\n",
"\n",
"We see this as raising $\\sqrt{2}$ to the power of $2$ results in an imprecise value as before!"
]
},
{
"cell_type": "code",
"execution_count": 173,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('1.999999999999999999999999999')"
]
},
"execution_count": 173,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"two = Decimal(2).sqrt() ** 2\n",
"\n",
"two"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"However, the [quantize()](https://docs.python.org/3/library/decimal.html#decimal.Decimal.quantize) method allows us to [quantize](https://www.dictionary.com/browse/quantize) (i.e., \"round\") a `Decimal` number at any precision that is *smaller* than the set precision. It takes the number of decimals to the right of the period of the `Decimal` argument we pass in and rounds accordingly.\n",
"\n",
"For example, as the overall imprecise value of `two` still has an internal precision of `28` digits, we can correctly round it to *four* decimals (i.e., `Decimal(\"0.0000\")` has four decimals)."
]
},
{
"cell_type": "code",
"execution_count": 174,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('2.0000')"
]
},
"execution_count": 174,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"two.quantize(Decimal(\"0.0000\"))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"We can never round a `Decimal` number and obtain a greater precision than before: The `InvalidOperation` exception tells us that *loudly*."
]
},
{
"cell_type": "code",
"execution_count": 175,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"ename": "InvalidOperation",
"evalue": "[<class 'decimal.InvalidOperation'>]",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mInvalidOperation\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-175-5b555b105c8f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtwo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mquantize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mDecimal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"1e-28\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mInvalidOperation\u001b[0m: [<class 'decimal.InvalidOperation'>]"
]
}
],
"source": [
"two.quantize(Decimal(\"1e-28\"))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Consequently, with this little workaround $\\sqrt{2}^2 = 2$ works, even in Python."
]
},
{
"cell_type": "code",
"execution_count": 176,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 176,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"two.quantize(Decimal(\"0.0000\")) == 2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The downside is that the entire expression is not as pretty as `sqrt(2) ** 2 == 2` from above."
]
},
{
"cell_type": "code",
"execution_count": 177,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 177,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(Decimal(2).sqrt() ** 2).quantize(Decimal(\"0.0000\")) == 2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`nan` and positive and negative `inf` exist as well, and the same remarks from above apply."
]
},
{
"cell_type": "code",
"execution_count": 178,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('NaN')"
]
},
"execution_count": 178,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"nan\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`Decimal(\"nan\")`s never compare equal to anything, not even to themselves."
]
},
{
"cell_type": "code",
"execution_count": 179,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 179,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"nan\") == Decimal(\"nan\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Infinity is larger than any concrete number."
]
},
{
"cell_type": "code",
"execution_count": 180,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('Infinity')"
]
},
"execution_count": 180,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"inf\")"
]
},
{
"cell_type": "code",
"execution_count": 181,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('-Infinity')"
]
},
"execution_count": 181,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"-inf\")"
]
},
{
"cell_type": "code",
"execution_count": 182,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Decimal('Infinity')"
]
},
"execution_count": 182,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"inf\") + 42"
]
},
{
"cell_type": "code",
"execution_count": 183,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 183,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Decimal(\"inf\") + 42 == Decimal(\"inf\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"As with `float` objects, we cannot add infinities of different signs: Now, get a module-specific `InvalidOperation` exception instead of a `nan` value. Here, **failing loudly** is a good thing as it prevents us from working with invalid results."
]
},
{
"cell_type": "code",
"execution_count": 184,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"ename": "InvalidOperation",
"evalue": "[<class 'decimal.InvalidOperation'>]",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mInvalidOperation\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-184-87950ebbd6ef>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mDecimal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"inf\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mDecimal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"-inf\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mInvalidOperation\u001b[0m: [<class 'decimal.InvalidOperation'>]"
]
}
],
"source": [
"Decimal(\"inf\") + Decimal(\"-inf\")"
]
},
{
"cell_type": "code",
"execution_count": 185,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"ename": "InvalidOperation",
"evalue": "[<class 'decimal.InvalidOperation'>]",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mInvalidOperation\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-185-996083f200c6>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mDecimal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"inf\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0mDecimal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"inf\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mInvalidOperation\u001b[0m: [<class 'decimal.InvalidOperation'>]"
]
}
],
"source": [
"Decimal(\"inf\") - Decimal(\"inf\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"For more information on the `Decimal` type, see the tutorial at [PYMOTW](https://pymotw.com/3/decimal/index.html) or the official [documentation](https://docs.python.org/3/library/decimal.html)."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## The `Fraction` Type"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"If the numbers in an application can be expressed as [rational numbers](https://en.wikipedia.org/wiki/Rational_number) (i.e., the set $\\mathbb{Q}$), we may model them as a [Fraction](https://docs.python.org/3/library/fractions.html#fractions.Fraction) type from the [fractions](https://docs.python.org/3/library/fractions.html) module in the [standard library](https://docs.python.org/3/library/index.html). As any fraction can always be formulated as the division of one integer by another, `Fraction` objects are inherently precise, just as `int` objects on their own. Further, we maintain the precision as long as we do not use them in a mathematical operation that could result in an irrational number (e.g., taking the square root).\n",
"\n",
"We import the `Fraction` type from the [fractions](https://docs.python.org/3/library/fractions.html) module."
]
},
{
"cell_type": "code",
"execution_count": 186,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"from fractions import Fraction"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Among others, there are two simple ways to create a `Fraction` object: We either instantiate one with two `int` objects representing the numerator and denominator or with a `str` object. In the latter case, we have two options again and use either the format \"numerator/denominator\" (i.e., *without* any spaces) or the same format as for `float` and `Decimal` objects above."
]
},
{
"cell_type": "code",
"execution_count": 187,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(1, 3)"
]
},
"execution_count": 187,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(1, 3) # 1 / 3 with \"full\" precision"
]
},
{
"cell_type": "code",
"execution_count": 188,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(1, 3)"
]
},
"execution_count": 188,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(\"1/3\") # 1 / 3 with \"full\" precision"
]
},
{
"cell_type": "code",
"execution_count": 189,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(3333333333, 10000000000)"
]
},
"execution_count": 189,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(\"0.3333333333\") # 1 / 3 with a precision of 10 significant digits"
]
},
{
"cell_type": "code",
"execution_count": 190,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(3333333333, 10000000000)"
]
},
"execution_count": 190,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(\"3333333333e-10\") # scientific notation is also allowed"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Only the lowest common denominator version is maintained after creation: For example, $\\frac{3}{2}$ and $\\frac{6}{4}$ are the same, and both become `Fraction(3, 2)`."
]
},
{
"cell_type": "code",
"execution_count": 191,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(3, 2)"
]
},
"execution_count": 191,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(3, 2)"
]
},
{
"cell_type": "code",
"execution_count": 192,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(3, 2)"
]
},
"execution_count": 192,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(6, 4)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"We could also cast a `Decimal` object as a `Fraction` object: This only makes sense as `Decimal` objects come with a pre-defined precision."
]
},
{
"cell_type": "code",
"execution_count": 193,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(1, 10)"
]
},
"execution_count": 193,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(Decimal(\"0.1\"))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`float` objects may *syntactically* be cast as `Fraction` objects as well. However, then we create a `Fraction` object that precisely remembers the `float` object's imprecision: A *bad* idea!"
]
},
{
"cell_type": "code",
"execution_count": 194,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(3602879701896397, 36028797018963968)"
]
},
"execution_count": 194,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(0.1)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`Fraction` objects follow the arithmetic rules from middle school and may be mixed with `int` objects *without* any loss of precision. The result is always a *new* `Fraction` object."
]
},
{
"cell_type": "code",
"execution_count": 195,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(7, 4)"
]
},
"execution_count": 195,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(3, 2) + Fraction(1, 4)"
]
},
{
"cell_type": "code",
"execution_count": 196,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(1, 2)"
]
},
"execution_count": 196,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(5, 2) - 2"
]
},
{
"cell_type": "code",
"execution_count": 197,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(1, 1)"
]
},
"execution_count": 197,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"3 * Fraction(1, 3)"
]
},
{
"cell_type": "code",
"execution_count": 198,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(1, 1)"
]
},
"execution_count": 198,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fraction(3, 2) * Fraction(2, 3)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`Fraction` and `float` objects may also be mixed *syntactically*. However, then the results may exhibit imprecision again, even if we do not see them at first sight! This is another example of code **failing silently**."
]
},
{
"cell_type": "code",
"execution_count": 199,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0.1"
]
},
"execution_count": 199,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"10.0 * Fraction(1, 100) # do not do this!"
]
},
{
"cell_type": "code",
"execution_count": 200,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'0.10000000000000000555111512312578270211815834045410'"
]
},
"execution_count": 200,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"format(10.0 * Fraction(1, 100), \".50f\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"For more examples and discussions, see the tutorial at [PYMOTW](https://pymotw.com/3/fractions/index.html) or the official [documentation](https://docs.python.org/3/library/fractions.html)."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## The `complex` Type"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"**What is the solution to $x^2 = -1$ ?**"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Some mathematical equations cannot be solved if the solution has to be in the set of the real numbers $\\mathbb{R}$. For example, $x^2 = -1$ can be rearranged into $x = \\sqrt{-1}$, but the square root is not defined for negative numbers. To mitigate this, mathematicians introduced the concept of an [imaginary number](https://en.wikipedia.org/wiki/Imaginary_number) $\\textbf{i}$ that is *defined* as $\\textbf{i} = \\sqrt{-1}$ or often as the solution to the equation $\\textbf{i}^2 = -1$. So, the solution to $x = \\sqrt{-1}$ then becomes $x = \\textbf{i}$.\n",
"\n",
"If we generalize the example equation into $(mx-n)^2 = -1 \\implies x = \\frac{1}{m}(\\sqrt{-1} + n)$ where $m$ and $n$ are constants chosen from the reals $\\mathbb{R}$, then the solution to the equation comes in the form $x = a + b\\textbf{i}$, the sum of a real number and an imaginary number, with $a=\\frac{n}{m}$ and $b = \\frac{1}{m}$.\n",
"\n",
"Such \"compound\" numbers are called **[complex numbers](https://en.wikipedia.org/wiki/Complex_number)**, and the set of all such numbers is commonly denoted by $\\mathbb{C}$. The reals $\\mathbb{R}$ are a strict subset of $\\mathbb{C}$ with $b=0$. Further, $a$ is referred to as the **real part** and $b$ as the **imaginary part** of the complex number.\n",
"\n",
"Complex numbers are often visualized in a plane like below, where the real part is depicted on the x-axis and the imaginary part on the y-axis."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"<img src=\"static/complex_numbers.png\" width=\"25%\" align=\"center\">"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`complex` numbers are part of core Python. The simplest way to create one is to write an arithmetic expression with the literal `j` notation for $\\textbf{i}$. The `j` is commonly used in many engineering disciplines instead of the symbol $\\textbf{i}$ from math as $I$ in engineering more often than not means [electric current](https://en.wikipedia.org/wiki/Electric_current).\n",
"\n",
"For example, the answer to $x^2 = -1$ can be written in Python as `1j` like below. This creates a `complex` object with value `1j`. The same syntactic rules apply as with the above `e` notation: No spaces are allowed between the number and the `j`. The number may be any `int` or `float` literal; however, it is stored as a `float` internally. So, `complex` numbers suffer from the same imprecision as `float` numbers."
]
},
{
"cell_type": "code",
"execution_count": 201,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"x = 1j"
]
},
{
"cell_type": "code",
"execution_count": 202,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"139960519210800"
]
},
"execution_count": 202,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"id(x)"
]
},
{
"cell_type": "code",
"execution_count": 203,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"complex"
]
},
"execution_count": 203,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(x)"
]
},
{
"cell_type": "code",
"execution_count": 204,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1j"
]
},
"execution_count": 204,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"To verify that it solves the equation, let's raise it to the power of $2$."
]
},
{
"cell_type": "code",
"execution_count": 205,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 205,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x ** 2 == -1"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Often, we write an expression of the form $a + b\\textbf{i}$."
]
},
{
"cell_type": "code",
"execution_count": 206,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(2+0.5j)"
]
},
"execution_count": 206,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"2 + 0.5j"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Alternatively, we may use the [complex()](https://docs.python.org/3/library/functions.html#complex) built-in: This takes two parameters where the second is optional and defaults to `0`. We may either call it with one or two arguments of any numeric type or a `str` object in the format of the previous code cell without any spaces."
]
},
{
"cell_type": "code",
"execution_count": 207,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(2+0.5j)"
]
},
"execution_count": 207,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"complex(2, 0.5)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"By omitting the second argument, we set the imaginary part to $0$."
]
},
{
"cell_type": "code",
"execution_count": 208,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(2+0j)"
]
},
"execution_count": 208,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"complex(2) "
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The arguments to [complex()](https://docs.python.org/3/library/functions.html#complex) may be any numeric type or properly formated `str` object."
]
},
{
"cell_type": "code",
"execution_count": 209,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(2+0.5j)"
]
},
"execution_count": 209,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"complex(Decimal(\"2.0\"), Fraction(1, 2))"
]
},
{
"cell_type": "code",
"execution_count": 210,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(2+0.5j)"
]
},
"execution_count": 210,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"complex(\"2+0.5j\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Arithmetic expressions work with `complex` numbers. They may be mixed with the other numeric types, and the result is always a `complex` number."
]
},
{
"cell_type": "code",
"execution_count": 211,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"c1 = 1 + 2j\n",
"c2 = 3 + 4j"
]
},
{
"cell_type": "code",
"execution_count": 212,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(4+6j)"
]
},
"execution_count": 212,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c1 + c2"
]
},
{
"cell_type": "code",
"execution_count": 213,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(-2-2j)"
]
},
"execution_count": 213,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c1 - c2"
]
},
{
"cell_type": "code",
"execution_count": 214,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(2+2j)"
]
},
"execution_count": 214,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c1 + 1"
]
},
{
"cell_type": "code",
"execution_count": 215,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(0.5-4j)"
]
},
"execution_count": 215,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"3.5 - c2"
]
},
{
"cell_type": "code",
"execution_count": 216,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(5+10j)"
]
},
"execution_count": 216,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"5 * c1"
]
},
{
"cell_type": "code",
"execution_count": 217,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(0.5+0.6666666666666666j)"
]
},
"execution_count": 217,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c2 / 6"
]
},
{
"cell_type": "code",
"execution_count": 218,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(-5+10j)"
]
},
"execution_count": 218,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c1 * c2"
]
},
{
"cell_type": "code",
"execution_count": 219,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(0.44+0.08j)"
]
},
"execution_count": 219,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c1 / c2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"A `complex` number comes with two **attributes** `real` and `imag` that return the two parts as `float` objects on their own."
]
},
{
"cell_type": "code",
"execution_count": 220,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0.0"
]
},
"execution_count": 220,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x.real"
]
},
{
"cell_type": "code",
"execution_count": 221,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1.0"
]
},
"execution_count": 221,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x.imag"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Also, a `conjugate()` method is bound to every `complex` object. The [complex conjugate](https://en.wikipedia.org/wiki/Complex_conjugate) is defined to be the complex number with identical real part but an imaginary part reversed in sign."
]
},
{
"cell_type": "code",
"execution_count": 222,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"-1j"
]
},
"execution_count": 222,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x.conjugate()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The [cmath](https://docs.python.org/3/library/cmath.html) module in the [standard library](https://docs.python.org/3/library/index.html) implements many of the functions from the [math](https://docs.python.org/3/library/math.html) module such that they work with complex numbers."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## The Numerical Tower"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Analogous to the discussion of *containers* and *iterables* in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Containers-vs.-Iterables), we contrast the *concrete* numeric data types in this chapter with the *abstract* ideas behind [numbers in mathematics](https://en.wikipedia.org/wiki/Number).\n",
"\n",
"The figure below summarizes five *major* sets of [numbers in mathematics](https://en.wikipedia.org/wiki/Number) as we know them from high school:\n",
"\n",
"- $\\mathbb{N}$: [Natural numbers](https://en.wikipedia.org/wiki/Natural_number) are all non-negative count numbers, e.g., $0, 1, 2, ...$\n",
"- $\\mathbb{Z}$: [Integers](https://en.wikipedia.org/wiki/Integer) are all numbers *without* a fractional component, e.g., $-1, 0, 1, ...$\n",
"- $\\mathbb{Q}$: [Rational numbers](https://en.wikipedia.org/wiki/Rational_number) are all numbers that can be expressed as a quotient of two integers, e.g., $-\\frac{1}{2}, 0, \\frac{1}{2}, ...$\n",
"- $\\mathbb{R}$: [Real numbers](https://en.wikipedia.org/wiki/Real_number) are all numbers that can be represented as a distance along a line, and negative means \"reversed,\" e.g., $\\sqrt{2}, \\pi, \\text{e}, ...$\n",
"- $\\mathbb{C}$: [Complex numbers](https://en.wikipedia.org/wiki/Complex_number) are all numbers of the form $a + b\\textbf{i}$ where $a$ and $b$ are real numbers and $\\textbf{i}$ is the [imaginary number](https://en.wikipedia.org/wiki/Imaginary_number), e.g., $0, \\textbf{i}, 1 + \\textbf{i}, ...$\n",
"\n",
"In the listed order, the five sets are perfect subsets of the respective following sets, and $\\mathbb{C}$ is the largest set. To be precise, all sets are infinite, but they still have a different number of elements."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"<img src=\"static/numbers.png\" width=\"75%\" align=\"center\">"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The data types introduced in this chapter are all *(im)perfect* models of *abstract* mathematical ideas.\n",
"\n",
"The `int` and `Fraction` types are the models \"closest\" to the idea they implement: Whereas $\\mathbb{Z}$ and $\\mathbb{Q}$ are, by definition, infinite, every computer runs out of bits when representing sufficiently large integers or fractions with a sufficiently large number of decimals. However, within a system-dependent range, we can model an integer or fraction without any loss in precision.\n",
"\n",
"For the other types, in particular, the `float` type, the implications of their imprecision are discussed in detail above.\n",
"\n",
"The abstract concepts behind the four outer-most mathematical sets are formalized in Python since [PEP 3141](https://www.python.org/dev/peps/pep-3141/) in 2007. The [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) defines what programmers call the **[numerical tower](https://en.wikipedia.org/wiki/Numerical_tower)**, a collection of five **[abstract data types](https://en.wikipedia.org/wiki/Abstract_data_type)**, or **abstract base classes** (ABCs) as they are called in Python jargon:\n",
"\n",
"- `Number`: \"any number\" (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Number))\n",
"- `Complex`: \"all complex numbers\" (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Complex))\n",
"- `Real`: \"all real numbers\" (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Real))\n",
"- `Rational`: \"all rational numbers\" (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Rational))\n",
"- `Integral`: \"all integers\" (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Integral))"
]
},
{
"cell_type": "code",
"execution_count": 223,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"import numbers"
]
},
{
"cell_type": "code",
"execution_count": 224,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"['ABCMeta',\n",
" 'Complex',\n",
" 'Integral',\n",
" 'Number',\n",
" 'Rational',\n",
" 'Real',\n",
" '__all__',\n",
" '__builtins__',\n",
" '__cached__',\n",
" '__doc__',\n",
" '__file__',\n",
" '__loader__',\n",
" '__name__',\n",
" '__package__',\n",
" '__spec__',\n",
" 'abstractmethod']"
]
},
"execution_count": 224,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dir(numbers)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Duck Typing (continued)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The primary purpose of ABCs is to classify the *concrete* data types and standardize how they behave. This guides us as the programmers in what kind of behavior we should expect from objects of a given data type. In this context, ABCs are not reflected in code but only in our heads.\n",
"\n",
"For, example, as all numeric data types are `Complex` numbers in the abstract sense, they all work with the built-in [abs()](https://docs.python.org/3/library/functions.html#abs) function (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Complex)). While it is intuitively clear what the [absolute value](https://en.wikipedia.org/wiki/Absolute_value) (i.e., \"distance\" from $0$) of an integer, a fraction, or any real number is, [abs()](https://docs.python.org/3/library/functions.html#abs) calculates the equivalent of that for complex numbers. That concept is called the [magnitude](https://en.wikipedia.org/wiki/Magnitude_%28mathematics%29) of a number, and is really a *generalization* of the absolute value.\n",
"\n",
"Relating back to the concept of **duck typing** mentioned in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Duck-Typing), `int`, `float`, and `complex` objects \"walk\" and \"quack\" alike in context of the [abs()](https://docs.python.org/3/library/functions.html#abs) function."
]
},
{
"cell_type": "code",
"execution_count": 225,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 225,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"abs(-1)"
]
},
{
"cell_type": "code",
"execution_count": 226,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42.87"
]
},
"execution_count": 226,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"abs(-42.87)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The absolute value of a `complex` number $x$ is defined with the Pythagorean Theorem where $\\lVert x \\rVert = \\sqrt{a^2 + b^2}$ and $a$ and $b$ are the real and imaginary parts."
]
},
{
"cell_type": "code",
"execution_count": 227,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"5.0"
]
},
"execution_count": 227,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"abs(3 + 4j)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"On the contrary, only `Real` numbers in the abstract sense may be rounded with the built-in [round()](https://docs.python.org/3/library/functions.html#round) function."
]
},
{
"cell_type": "code",
"execution_count": 228,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"100"
]
},
"execution_count": 228,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"round(123, -2)"
]
},
{
"cell_type": "code",
"execution_count": 229,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42"
]
},
"execution_count": 229,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"round(42.1)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`Complex` numbers are two-dimensional. So, rounding makes no sense here and leads to a `TypeError`. So, in the context of the [round()](https://docs.python.org/3/library/functions.html#round) function, `int` and `float` objects \"walk\" and \"quack\" alike whereas `complex` objects do not."
]
},
{
"cell_type": "code",
"execution_count": 230,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "TypeError",
"evalue": "type complex doesn't define __round__ method",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-230-e40cd01fb15a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mround\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m2j\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m: type complex doesn't define __round__ method"
]
}
],
"source": [
"round(1 + 2j)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Goose Typing"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Another way to use ABCs is in place of a *concrete* data type.\n",
"\n",
"For example, we may pass them as arguments to the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function and check in which of the five mathematical sets the object `1 / 10` is."
]
},
{
"cell_type": "code",
"execution_count": 231,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 231,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(1 / 10, float)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"A `float` object is a generic `Number` in the abstract sense but may also be seen as a `Complex` or `Real` number."
]
},
{
"cell_type": "code",
"execution_count": 232,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 232,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(1 / 10, numbers.Number)"
]
},
{
"cell_type": "code",
"execution_count": 233,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 233,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(1 / 10, numbers.Complex)"
]
},
{
"cell_type": "code",
"execution_count": 234,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 234,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(1 / 10, numbers.Real)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Due to the `float` type's inherent imprecision, `1 / 10` is *not* a `Rational` number."
]
},
{
"cell_type": "code",
"execution_count": 235,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 235,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(1 / 10, numbers.Rational)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"However, if we model `1 / 10` as a `Fraction` object, it is recognized as a `Rational` number."
]
},
{
"cell_type": "code",
"execution_count": 236,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 236,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(Fraction(\"1/10\"), numbers.Rational)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Replacing *concrete* data types with ABCs is particularly valuable in the context of \"type checking:\" The revised version of the `factorial()` function below allows its user to take advantage of *duck typing*: If a real but non-integer argument `n` is passed in, `factorial()` tries to cast `n` as an `int` object with the [int()](https://docs.python.org/3/library/functions.html#int) built-in.\n",
"\n",
"Two popular and distinguished Pythonistas, [Luciano Ramalho](https://github.com/ramalho) and [Alex Martelli](https://en.wikipedia.org/wiki/Alex_Martelli), coin the term **goose typing** to specifically mean using the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function with an ABC (cf., Chapter 11 in this [book](https://www.amazon.com/Fluent-Python-Concise-Effective-Programming/dp/1491946008) or this [summary](https://dgkim5360.github.io/blog/python/2017/07/duck-typing-vs-goose-typing-pythonic-interfaces/) thereof)."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"#### Example: [Factorial](https://en.wikipedia.org/wiki/Factorial) (revisited)"
]
},
{
"cell_type": "code",
"execution_count": 237,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"def factorial(n, *, strict=True):\n",
" \"\"\"Calculate the factorial of a number.\n",
"\n",
" Args:\n",
" n (int): number to calculate the factorial for; must be positive\n",
" strict (bool): if n must not contain decimals; defaults to True;\n",
" if set to False, the decimals in n are ignored\n",
"\n",
" Returns:\n",
" factorial (int)\n",
"\n",
" Raises:\n",
" TypeError: if n is not an integer or cannot be cast as such\n",
" ValueError: if n is negative\n",
" \"\"\"\n",
" if not isinstance(n, numbers.Integral):\n",
" if isinstance(n, numbers.Real):\n",
" if n != int(n) and strict:\n",
" raise TypeError(\"n is not integer-like; it has non-zero decimals\")\n",
" n = int(n)\n",
" else:\n",
" raise TypeError(\"Factorial is only defined for integers\")\n",
"\n",
" if n < 0:\n",
" raise ValueError(\"Factorial is not defined for negative integers\")\n",
" elif n == 0:\n",
" return 1\n",
" return n * factorial(n - 1)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`factorial()` works as before, but now also accepts, for example, `float` numbers."
]
},
{
"cell_type": "code",
"execution_count": 238,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 238,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"factorial(0)"
]
},
{
"cell_type": "code",
"execution_count": 239,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"6"
]
},
"execution_count": 239,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"factorial(3)"
]
},
{
"cell_type": "code",
"execution_count": 240,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"6"
]
},
"execution_count": 240,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"factorial(3.0)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"With the keyword-only argument `strict`, we can control whether or not a passed in `float` object may come with decimals that are then truncated. By default, this is not allowed and results in a `TypeError`."
]
},
{
"cell_type": "code",
"execution_count": 241,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"ename": "TypeError",
"evalue": "n is not integer-like; it has non-zero decimals",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-241-188b816be8b6>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-237-be6602f598f7>\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n, strict)\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mReal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mstrict\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not integer-like; it has non-zero decimals\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 20\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mTypeError\u001b[0m: n is not integer-like; it has non-zero decimals"
]
}
],
"source": [
"factorial(3.1)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"In non-strict mode, the passed in `3.1` is truncated into `3` resulting in a factorial of `6`."
]
},
{
"cell_type": "code",
"execution_count": 242,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"6"
]
},
"execution_count": 242,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"factorial(3.1, strict=False)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"For `complex` numbers, `factorial()` still raises a `TypeError` because they are neither an `Integral` nor a `Real` number."
]
},
{
"cell_type": "code",
"execution_count": 243,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"ename": "TypeError",
"evalue": "Factorial is only defined for integers",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-243-7296a74f5dcf>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m2j\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-237-be6602f598f7>\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n, strict)\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 22\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 23\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mTypeError\u001b[0m: Factorial is only defined for integers"
]
}
],
"source": [
"factorial(1 + 2j)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"## TL;DR"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"There exist three numeric types in core Python:\n",
"- `int`: a near-perfect model for whole numbers (i.e., $\\mathbb{Z}$); inherently precise\n",
"- `float`: the \"gold\" standard to approximate real numbers (i.e., $\\mathbb{R}$); inherently imprecise\n",
"- `complex`: layer on top of the `float` type to approximate complex numbers (i.e., $\\mathbb{C}$); inherently imprecise\n",
"\n",
"Furthermore, the [standard library](https://docs.python.org/3/library/index.html) provides two more types that can be used as substitutes for the `float` type:\n",
"- `Decimal`: similar to `float` but allows customizing the precision; still inherently imprecise\n",
"- `Fraction`: a near-perfect model for rational numbers (i.e., $\\mathbb{Q}$); built on top of the `int` type and therefore inherently precise\n",
"\n",
"The *important* takeaways for the data science practitioner are:\n",
"\n",
"1. **Do not mix** precise and imprecise data types, and\n",
"2. actively expect `nan` results when working with `float` numbers as there are no **loud failures**.\n",
"\n",
"The **numerical tower** is Python's way of implementing various **abstract** ideas of what numbers are in mathematics."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"## Further Resources"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The two videos below show how addition and multiplication works with numbers in their binary representations. Subtraction is a bit more involved as we need to understand how negative numbers are represented in binary with the concept of [Two's Complement](https://en.wikipedia.org/wiki/Two%27s_complement) first. A video on that is shown further below. Division in binary is actually also quite simple."
]
},
{
"cell_type": "code",
"execution_count": 244,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAcICAgICAgJCAgIBwgICAgICAgICAgICAgICAgICAgIChALCAgOCQgIDRUODhERExMTCAsXGBYSGBASExIBBQUFBwYHDwkJDxcVEhUXFRMVFxUYFRUVFRUVFRcYFRUVGBUXFRIVFhUXFxcVFRUXGBYVFxUVFRUVFRYVFRUSFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAQUBAQEAAAAAAAAAAAAAAQQFBgcIAwIJ/8QAVxAAAQQBAwIDBAQHCQsJCQEAAQACAwQRBQYSEyEHCDEUIkFRCTJhcRUjNkJSgZEzYnJzdHWhtLUWJDQ1Y3aCorGzwjdDRFNVh5LBxCaDk5SjssPR1Bj/xAAbAQEBAQEAAwEAAAAAAAAAAAAAAQIDBAYHBf/EAC8RAQEAAgAEBAIJBQAAAAAAAAABAhEDEiExBAVBUTJxBiJhgZGhsdHwFCNSweH/2gAMAwEAAhEDEQA/AOMkREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCEU4TCCUREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQFUdEdHqd89Thj4Y48h/5qnVZAc1pR+hLE79ThI0/08VrGb/NvCb38qoyiIssCIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAAiq6E7mnixjHSPcA1zm8iM9sNDuwz88Jq3DrP444h2PdxjIADsY+HIFb5fq7b5fq7UiKqsRBjGD1e4c3fvWn6jcD4kd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\n",
"text/html": [
"\n",
" <iframe\n",
" width=\"60%\"\n",
" height=\"300\"\n",
" src=\"https://www.youtube.com/embed/RgklPQ8rbkg\"\n",
" frameborder=\"0\"\n",
" allowfullscreen\n",
" ></iframe>\n",
" "
],
"text/plain": [
"<IPython.lib.display.YouTubeVideo at 0x7f4b19022490>"
]
},
"execution_count": 244,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"YouTubeVideo(\"RgklPQ8rbkg\", width=\"60%\")"
]
},
{
"cell_type": "code",
"execution_count": 245,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"image/jpeg": "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OVfTdF7GINmCsLIdz60jfXrt2239Ctd+POs6+odQ5LMVopYIMi+u6OKxw6rRDUr1zz6bnN3LoXHsT2IWDogKw3kCw2Rn1W21VeY6uMpWHZN227ZYrDDFDVP9Z04jlH/lXH4KvKs95ZPHrS2kMNNWlo5Szk71mSzcmhhpCu4tHTq145X2GydBsY5buYSHTS7AjYIOx+US197TkaWnoZN4sQz2y+1pBBu2WbV2P+IdHVcXf/en12G1UF2+s9QWMrkbuStO5T5K3NZl7ucGmZ5eI2cu4jY0hjR8GsaPguoQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQERAgKeP+Sy/Rfh7kMlxk4+zVj62ZmnZw/8GPs6X8vZvr3W7dKaKx2ObtDCJZXNIfYsNbJK7f6TR22Yz7mgffv6rkw4WWXd571T8S8n6fej+LP2x/zfl979FYiEW+daeFVO2HTUS2pOdz0tj7LIfzW7mH8rdx/VWmtQ4C3Ql6NuF0TvxSdiyQD1dHIPde309D8e+ymeGWHl2/S/W+U9Sx/c5fF88b5/3PrHVoiLD9YRNvgiAiIgIiICIiAiljSewBJAJ2Hc7NBc4/kABJ/IoQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQF2mko2vv0WPaHMkvVWva4btc107A5rgexBBIXVrttG/6xx/6QqfvEas8uHmLrg5We1/st3SwV+aB1iCpPLXjcWOlhifI1rmtaSHCMEtADm99tgCtweXGTHCrZG8TbxsHq9QsEprcGdPhv3MXLqb/AH+vwXy8teajDLePc4CTqe1wNP47XNZFKG/e0xxn/wBQ/Yvp49aHidGMnViAmEscdqONoAm672xRy8f+96jmNJ+IfufTv2s8t3or516T6f8AsnLY+q8v8dkvVjfvq+886s8ffX/ihBWnzdmPFx9VryzeOmwyNfOGjrGJkQPL3vXj+NyWqPHn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P+1d9y1iiDYevPGPUeTyd2+zK5GnHdsySQ062QtRQ1od+MMDGRPazZkbWN3AHIgk9ys88G/MOcfi8th9RxXc7SzLXNYX2zJYhbNC6CzH1bRcem5gic0N24ua8/jdtAIgsR4L+YytQxDdO6lxLc5iIhtX3EUk0UbX9SOB8NkdOeNj+7HcmuZsANwG8fj4ueYKjbixVHTeDrYijgclBlazpoIOt7ZXkEsfSjg9ytGX7l7g5z5OwJaAQ6vqILW6k8yekLtirnZdKST6moQMZVmsWR7DDLG4vik3Y/eYRyOc9pdCHj0Dm9iNeeIXjzYt6vrarxVd1OWnWrwitacJWyhkckdiKXp7coZGyvZ22O2xGx220qiC3eT802k5Hty7dItdqSOJoit2BUfHFM1vBj/bA3rvawdgem12w4gt9Rqfxh8cbGX1Hi9SY6F+PuYihUha17hI02IJrM0rgB613+0uj4nuW8t/VacRBbex5mdF5Aw5HM6ObZzdZjQJmspzQufF3jPXn2kDAe4D2PLN+xO251d4deM9TG6ys6okxTYoLnte+Mxzw1sJsxhu7HSjZzi8F7js0F0jiA0bNGmUQbdwHi5Wra7fq51OZ1d967Z9hbIzrhtqpPWa3qEcOQMwcfzSFOV8Xa02vG6vFOYVm3q1n2EyM6/CCpFVLee3DkTGXf37LUKINr+K+uJdW6vgyOJglp2b1jGVcfFK9jpW24zDDA/k0cRvNxI9fRWT+UH12+nh6OAZIDZzUjbF/h2HsdQtIHEndrZbfEj17VnhVA8JdZu09l6uXZUhuS0Oq6GCy57Y+pJE+Jsh6Z35N6hI+8D7iPv4yeId3VGWmy1xjInyxwww1oi50VeGFnFscZf7xBeZJDv+NK78iDDUREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEUbpuglFG6boJRRum6CUUbpuglFG6boJRRum6CUUbpuglFG6boJRRum6CUUbpuglFG6boJRRum6CUUbpuglFG6boJRRum6CUUbpuglFG6boJRRum6CUUbpuglFG6boJRRum6CUUbpuglFG6boJRRum6CUUbpuglFG6boJRRum6CUUbpuglFG6boJRRum6CEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQf/9k=\n",
"text/html": [
"\n",
" <iframe\n",
" width=\"60%\"\n",
" height=\"300\"\n",
" src=\"https://www.youtube.com/embed/xHWKYFhhtJQ\"\n",
" frameborder=\"0\"\n",
" allowfullscreen\n",
" ></iframe>\n",
" "
],
"text/plain": [
"<IPython.lib.display.YouTubeVideo at 0x7f4b1901cc50>"
]
},
"execution_count": 245,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"YouTubeVideo(\"xHWKYFhhtJQ\", width=\"60%\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The video below explains the idea behind [Two's Complement](https://en.wikipedia.org/wiki/Two%27s_complement). This is how most modern programming languages implement negative integers. The video also shows how subtraction in binary works."
]
},
{
"cell_type": "code",
"execution_count": 246,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"image/jpeg": "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\n",
"text/html": [
"\n",
" <iframe\n",
" width=\"60%\"\n",
" height=\"300\"\n",
" src=\"https://www.youtube.com/embed/4qH4unVtJkE\"\n",
" frameborder=\"0\"\n",
" allowfullscreen\n",
" ></iframe>\n",
" "
],
"text/plain": [
"<IPython.lib.display.YouTubeVideo at 0x7f4b190196d0>"
]
},
"execution_count": 246,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"YouTubeVideo(\"4qH4unVtJkE\", width=\"60%\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"This video by the YouTube channel [Computerphile](https://www.youtube.com/channel/UC9-y-6csu5WGm29I7JiwpnA) explains floating point numbers in an intuitive way with some numeric examples."
]
},
{
"cell_type": "code",
"execution_count": 247,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"image/jpeg": "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\n",
"text/html": [
"\n",
" <iframe\n",
" width=\"60%\"\n",
" height=\"300\"\n",
" src=\"https://www.youtube.com/embed/PZRI1IfStY0\"\n",
" frameborder=\"0\"\n",
" allowfullscreen\n",
" ></iframe>\n",
" "
],
"text/plain": [
"<IPython.lib.display.YouTubeVideo at 0x7f4b190160d0>"
]
},
"execution_count": 247,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"YouTubeVideo(\"PZRI1IfStY0\", width=\"60%\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Below is a short introduction to [complex numbers](https://en.wikipedia.org/wiki/Complex_number) by [MIT](https://www.mit.edu) professor [Gilbert Strang](https://en.wikipedia.org/wiki/Gilbert_Strang) aimed at high school students."
]
},
{
"cell_type": "code",
"execution_count": 248,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"image/jpeg": "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\n",
"text/html": [
"\n",
" <iframe\n",
" width=\"60%\"\n",
" height=\"300\"\n",
" src=\"https://www.youtube.com/embed/Jkv-55ndVYY\"\n",
" frameborder=\"0\"\n",
" allowfullscreen\n",
" ></iframe>\n",
" "
],
"text/plain": [
"<IPython.lib.display.YouTubeVideo at 0x7f4b1907e190>"
]
},
"execution_count": 248,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"YouTubeVideo(\"Jkv-55ndVYY\", width=\"60%\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.7.4"
},
"livereveal": {
"auto_select": "code",
"auto_select_fragment": true,
"scroll": true,
"theme": "serif"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": true,
"skip_h1_title": true,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {
"height": "calc(100% - 180px)",
"left": "10px",
"top": "150px",
"width": "384px"
},
"toc_section_display": false,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}