{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "# Python入門講座第5回 : 流れを意のままに"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## きょうの目標 \n",
    "\n",
    "今日の講座では、`while`文による繰り返しで、フィボナッチ関数を再定義してみます。\n",
    "\n",
    "* * * *\n",
    "- python3の制御構造：`while`文\n",
    "  - `if`文,`while`文, `for`文: 制御文／制御構造\n",
    "      - `break`/`continue`/`pass`/`...`(Ellipsis)\n",
    "  - 論理式：　\n",
    "\n",
    "- 代入式\n",
    "  - 代入文との違い\n",
    "\n",
    "- 実行時間の測定：`timeit`モジュール\n",
    "* * * *\n",
    "\n",
    "などについてご説明します。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "## `fib（）`関数の別定義\n",
    "これまで使ってきた漸化式を元にしたフィボナッチ数列の関数は次のような物でした。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def fibr(n:int)->int:\n",
    "    \"\"\"\n",
    "    returns the n-th fibonacci number.\n",
    "    \"\"\"\n",
    "    if n in (0,1):\n",
    "        return 1\n",
    "    return fibr(n-1) + fibr(n-2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "この再帰的に定義された`fibr(n)`は大きな`n`に対して、効率が悪く、実行速度も遅いという問題があります。\n",
    "そこで、*再帰*を*繰り返し*に展開したフィボナッチ関数を次に示します。\n",
    "Pythonの繰り返しには`for`文もありましたが、ここでは`while`文を使って書いてみました。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "> Notes:\n",
    "> \n",
    "> この実装は　[Python.org](https://www.python.org/) に掲載されている$n$を超えない最大のフィボナッチ数を求める関数を少し変形して、$n$番目のフィボナッチ数を求める関数に書き換えたものです。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "新しいフィボナッチ数列の定義は次のようになりました。\n",
    "この定義ではPython3の**代入式**と **`while`文** が使われています。これらの文法について次に解説します。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def fib(n:int)->int:\n",
    "    \"\"\"\n",
    "    returns the n-th fibonacci number.\n",
    "    \"\"\"\n",
    "    if n in (0, 1):\n",
    "        return 1\n",
    "    a=b=1 \n",
    "    while (n := n-1 ) > 0:\n",
    "        a, b = a+b, a # a: f_{k}, b:f_{k-1}\n",
    "    return a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "二つのフィボナッチ数列を求める関数(`fib`, `fibr`)の値を比較してみましょう。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "n=0 fib(n)=1 fibr(n)=1\n",
      "n=1 fib(n)=1 fibr(n)=1\n",
      "n=2 fib(n)=2 fibr(n)=2\n",
      "n=3 fib(n)=3 fibr(n)=3\n",
      "n=4 fib(n)=5 fibr(n)=5\n",
      "n=5 fib(n)=8 fibr(n)=8\n"
     ]
    }
   ],
   "source": [
    "print(\"\\n\".join([f\"{n=:} {fib(n)=:} {fibr(n)=:}\" for n in range(6)]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "このように二つの関数の値は一致します。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "この関数では、一時変数　a,b　に　フィボナッチ数列のある時点での値と一つ前の値を保存します。\n",
    "その時次のステップでの フィボナッチ数列の値は、`a+b`, 一つ前のフィボナッチ数列の値は　`a`です。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": []
   },
   "source": [
    "| i | 1 | 2 | 3 |4 |...|n-1| n |\n",
    "|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n",
    "| f_{i}　| 1| 2 | 3 | 5 |...| a| a+b|\n",
    "| f_{i-1} | 1| 1 | 2 |3  |...|b| a|\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "例えば、`i=3`の時、`a`は3、`b`は2となっています。\n",
    "``` python\n",
    "a,　b = a+b, a\n",
    "```\n",
    "を実行すると、`a`は5、`b`は3となって、　`i=4`のフィボナッチ数列の値と、一つ前のフィボナッチ数列になります。\n",
    "これを `n-1`回繰り返すと、`fib(n)`が求まるというわけです。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "> Note:\n",
    ">\n",
    "> ここでもし、ループの中が次のようなプログラムだったとします。\n",
    ">\n",
    ">```python\n",
    ">a=a+b\n",
    ">b=a\n",
    ">```\n",
    ">\n",
    ">`i=3`で`a`が3、`b`は2の時にこのプログラムを実行すると,\n",
    ">プログラムの実行後は　`a`は5となりますが、`b`も5になってしまいます。\n",
    ">\n",
    ">ループの中身を\n",
    ">``` python\n",
    ">b=a\n",
    ">a=a+b\n",
    ">```\n",
    ">とすると、今度は、実行後の値は`b`は3, `a`は　6 (= 3+3)になってしまいます。\n",
    ">\n",
    ">これを避けるためには、ループ中のプログラムを\n",
    ">\n",
    ">``` python\n",
    ">t=a\n",
    ">a=a+b\n",
    ">b=t\n",
    ">```\n",
    ">\n",
    ">とすることもできますが、pythonでは、\n",
    ">\n",
    ">``` python\n",
    ">a,b = a+b,b\n",
    ">```\n",
    ">と簡単に書くことができます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[fibr(n) for n in range(10)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "> Note:\n",
    "> `for文`を使ったバージョンはこちら。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 1, 2, 3, 5, 8]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def fibl(n:int)->int:\n",
    "    \"\"\"\n",
    "    returns the n-th fibonacci number.\n",
    "    \"\"\"\n",
    "    if n in (0, 1):\n",
    "        return 1\n",
    "    a=b=1\n",
    "    for i in range(1,n):\n",
    "        a, b = b, a+b\n",
    "    return b\n",
    "\n",
    "[fibl(n) for n in range(6)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "## Pythonの制御構造\n",
    "まず、関数定義の中の、`while`文から見ていきましょう。\n",
    "\n",
    "`while`文は、`if`文、`for`文と同じく、Pythonでのプログラムの流れを制御するための文です。\n",
    "\n",
    "- `if`文は条件分岐を作ります。\n",
    "- `while`文と`for`文は繰り返し(ループ）を作ります。\n",
    "\n",
    "C言語などではこのほかにも,`repeat-until`構文、`do-while`構文、`switch-case`構文などをもつ言語もありますが、pythonの制御構造はこの三つ(`if`, `for`,`while`)だけです。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "| 逐次実行 | if文　| for文 | while 文 |\n",
    "|:--|:--|:--|:--|\n",
    "|<文><br/><文...>| if <式>:<br/>&nbsp;&nbsp;<文...><br/>else:<br/>&nbsp;&nbsp;<文...> | for `var` in `iterable` :<br/>&nbsp;&nbsp;<文...> <br/>else: <br/>&nbsp;&nbsp;<文...>  |while <式>: <br/>&nbsp;&nbsp;<文...> <br/> else: <br/>&nbsp;&nbsp;<文...> | \n",
    "|![逐次実行]|![if文]|![for文]|![while文]|\n",
    "\n",
    "[逐次実行]:_images/逐次実行文.png\n",
    "\n",
    "[if文]: ./_images/if文.png\n",
    "\n",
    "[while文]: ./_images/while文.png\n",
    "\n",
    "[for文]: ./_images/for文.png"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "> Notes:\n",
    "構造化定理（こうぞうかていり、英: Structure theorem）とは、任意の一入力・一出力関数は、順次（sequence）、選択（ifthenelse）、繰り返し（whiledo）の３つの基本制御構造からなる関数と等価であることを主張する定理である[1]。構造化プログラム定理（structured program theorem） あるいは ベーム-ヤコピーニの定理（Böhm-Jacopini theorem）とも呼ばれる.(wikipediaより）\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### `if`文：\n",
    "\n",
    "```python\n",
    "if <式> :\n",
    "    <プログラムブロック-1>\n",
    "elif <式-2> :\n",
    "    <プログラムブロック-2>\n",
    "else:\n",
    "    <プログラムブロック->\n",
    "```\n",
    "- `elif`節は必要なだけ繰り返してもよい。 (なくてもよい）\n",
    "  - `elif` は`else-if`の省略\n",
    "- `else`節はなくてもよいが、一つの`if`文には二つ以上あってはいけない。\n",
    "\n",
    "<式>が論理値として真(`True`)になった時、対応する<プログラムブロックを実行する。\n",
    "`if`あるいは`else`節に指定されたどの式も論理値としての値が偽(`False`)の場合、`else`節の<プログラムブロック>が実行される。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "|if-elif-else文 |\n",
    "|:-----|\n",
    "| if <条件>:<br/>&nbsp;&nbsp;<文> ...<br/>elif <条件>:<br/>&nbsp;&nbsp;<文> <br/> ...<br/>else:<br/>&nbsp;&nbsp;<文>\n",
    "|![if-elif-else文]|\n",
    "\n",
    "\n",
    "[if-elif-else文]: ./_images/if-elif-else文.png"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### `for`文：\n",
    "- 第一形態： \n",
    "```python\n",
    "for <識別子> in <> <繰り返し指定> :\n",
    "    <プログラムブロック>\n",
    "```\n",
    "1. <繰り返し指定> の要素を<識別子>に設定して、<プログラムブロック>を実行します。\n",
    "1. 要素がなくなれば, `for`文は終了します。\n",
    " \n",
    "- 第二形態：\n",
    "```python\n",
    "for <識別子> in <> <繰り返し指定> :\n",
    "    <プログラムブロック-1>\n",
    "else:\n",
    "    <プログラムブロック-2>\n",
    "```\n",
    "1.  <繰り返し指定> の要素を<識別子>に設定して、<プログラムブロック-1>を実行します。\n",
    "1.  要素がなくなれば、<プログラムブロック-2>を実行して、`for`文を終了します。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### while文\n",
    "- 第一形態：\n",
    "```python\n",
    "while <式> :\n",
    "    <プログラムブロック>\n",
    "```\n",
    "1. `<式>`の値が真であれば、`<プログラム　ブロック>` を実行して、ループを繰り返します。\n",
    "\n",
    "- 第ニ形態：\n",
    "```python\n",
    "while <式> :\n",
    "    <プログラムブロック1>\n",
    "else:\n",
    "    <プログラムブロック2>\n",
    "```\n",
    "1. `<式>`の論理値としての値が真であれば、`<プログラム　ブロック1>` を実行して、ループを**繰り返す**。\n",
    "1. `<式>`の論理値としての値が偽であれば、`<プログラム　ブロック2>` を実行して、ループを**終了**する。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### `break`文/`continue`文/`pass`文/`...` (Ellipsis)\n",
    "\n",
    "`while`や`for`で作られたループを処理の途中で中断し、次の要素に進んだり、ループを抜け出すこともできます。\n",
    "`continue`および`break`はこれらの目的に用意されています。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "![Books](./_images/Books_on_the_shelf.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "> Note:\n",
    "書棚の本から目的とする本を内容を確認しながら、探すことを考えてみましょう。\n",
    "書棚から順> 番に、\n",
    "> \n",
    "> 1. **始：** 書籍を手に取ります。\n",
    "> 1. タイトルをみて、目的の書籍でないことが明らかなら、次の本をチェックします。(`continue`)\n",
    "> 1. 内容をチェックして、目的の本であることがわかれば、ここで探索を終了します。(`break`)\n",
    ">    - 書棚にチェックしていない本がまだあっても、作業を終了します。\n",
    "> 1. 次の書籍がまだあれば、 **始:** に戻ります。\n",
    "> 1. 書棚の書籍がもうなければ(`else`節）、この書棚には目的の本はないということです.\n",
    "> さあどうしましょう？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### `break`文/`continue`文/`pass`文/`...` (Ellipsis)\n",
    "\n",
    "`while`や`for`で作られたループを処理の途中で中断し、次の要素に進んだり、ループを抜け出すこともできます。\n",
    "`continue`および`break`はこれらの目的に用意されています。\n",
    "\n",
    "#### `break`/`continue`\n",
    "`while`文、`for`文の(`else`節を除く）　<プログラム　ブロック>は`break`文あるいは`continue`文　を含むことがあります。\n",
    "\n",
    "- `break`文は`break`, `continue`文は`continue`だけ含む文です。\n",
    "- `continue`文が実行されると、プログラムブロックの実行はそこで終了し、次の**繰り返し**に制御が移ります。\n",
    "- `break`文が実行されると、プログラムブロックの実行はそこで終了し、`while`文あるいは`for`文の**次の文**に制御が移ります。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "| for文 + coninue/break | | while 文 + coninue/break |\n",
    "|:-------:| :--: | :-------:|\n",
    "| ![for-beak文] |`    ` | ![while-break文] |\n",
    "|  |  |\n",
    "\n",
    "[for-beak文]: ./_images/for-continue-break文.png\n",
    "\n",
    "[while-break文]: ./_images/While-continue-break文.png\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "#### `pass`文/`...` (Ellipsis)\n",
    "\n",
    "プログラム開発中には、詳細は後々に埋めることとして、全体の枠組みだけを作っていくことがあります。`pass`文や`...`(Ellipsis)はそのような場合の埋め草として使われます。たとえば、\n",
    "\n",
    "``` python\n",
    "while condition :\n",
    "    do_something()\n",
    "else:\n",
    "    pass\n",
    "\n",
    "def do_something(arg):\n",
    "    ...\n",
    "```\n",
    "\n",
    "といった具合です。`pass`文も`...` も **何もしない(No-op)** を表現しています。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "## 代入文と代入式\n",
    "次に、代入式　`(n := n-1 )`　を　見ていきましょう。\n",
    "\n",
    "### 式文\n",
    "以下の形式のプログラム中の行は 式文　と呼ばれます。\n",
    "```\n",
    "    <式＞　\n",
    "    <式＞　, <式>, ...\n",
    "```\n",
    "式文では、`式`を評価します。　対話モードのPythonでは式の評価後の値(あるいは式のタプル）を印刷します。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### 代入文(assignment statement)\n",
    "\n",
    "``` python\n",
    "    a = b = 1\n",
    "\n",
    "    a = 1\n",
    "    b = 1\n",
    "    \n",
    "    a, b = 1, 1\n",
    "```\n",
    "などの文は**代入文**です。\n",
    "\n",
    "**代入文**は変数に式を評価した値を割り当てます。\n",
    "（Pythonでは代入文より割り当て文と呼んだほうがいいかもしれない。個人的見解です)\n",
    "``` python\n",
    "    <識別子> = <式> 　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　\n",
    "    <識別子> = <識別子> =... = <式> \n",
    "    <識別子> , <識別子>, ... 　= <式>, <式>,... #式の左右で要素の数が一致していること\n",
    "    <識別子> , <識別子>, ... 　= <シークエンス>   #識別子の数とシークエンスの要素数は一致していること\n",
    "    <識別子0> , <識別子1>,...,*<識別子n> = <シークエンス>　　#シークエンスの要素数　は`n`以上\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "Pythonの代入文はC言語のそれと異なり、値を持ちません。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "###　代入式 assignment expression　`(n := n-1)`\n",
    "walrus(セイウチ）  expression とも呼ばれます。　\n",
    "`while`文、`if`文などの条件節で、代入式(`<識別子> := <式>`)を使うことができます。\n",
    "\n",
    "代入式では`<識別子>`への`<式>`の代入を行い、その式の値が代入式の値となります。"
   ]
  },
  {
   "attachments": {
    "eb5c5cdd-cca5-492e-8593-7afa2021989f.jpeg": {
     "image/jpeg": "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"
    }
   },
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "|walrus(セイウチ）|\n",
    "|:---:|\n",
    "|![セイウチ](attachment:eb5c5cdd-cca5-492e-8593-7afa2021989f.jpeg)|\n",
    "([image source:](https://commons.wikimedia.org/wiki/File:Noaa-walrus22.jpg) )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "89\n"
     ]
    }
   ],
   "source": [
    "# 例\n",
    "if (v:=fib(10)) > 0:\n",
    "    print(v)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "> Note:\n",
    "代入式 , walrus(セイウチ）  expression はpython 3.8で導入されました。\n",
    "> \n",
    "> C-言語では代入文はなく、元々代入式であったので、なにを今更という感じかもしれません。\n",
    "> \n",
    "> ``` python\n",
    "> if v:=fib(10) > 0:\n",
    ">     print(v)\n",
    "> ```\n",
    "はエラーにはなりませんが\n",
    "> ``` python\n",
    "> if v:=(fib(10) > 0):\n",
    ">     print(v)\n",
    "> ```\n",
    "と解釈されてしまうので、注意が必要です。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "## 比較演算子\n",
    "`if`文、`while`文には 分岐／継続のための条件式が必要です。\n",
    "条件式は比較演算子や論理演算子を組み合わせてつくることができます。\n",
    "値の比較はC言語とほぼ同じです。 比較の結果はブール値(`True` または　 `False`)です。\n",
    "\n",
    "```\n",
    "    <式> == <式>　　　　　　　　# 　右辺と左辺は同じ値\n",
    "    <式> != <式>　　　　　　　　# 　右辺と左辺は異なる値\n",
    "    <式> > <式>\n",
    "    <式> >= <式>\n",
    "    <式> < <式>\n",
    "    <式> <= <式>\n",
    "    <式> in <式>　　　　　　　　　　　# 左辺が右辺の要素にふくまれる。　 （例：　n in (0,1))\n",
    "    <式> not in <式>　　　# 左辺は右辺の要素に含まれない。 (例：　n not in (0,1))\n",
    "    <式> is <式> 　　　　　　　　　# 右辺と左辺は同じオブジェクト\n",
    "    <式> is not <式>　　　# 右辺と左辺は異なるオブジェクト\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### オブジェクトの等価性(`=　=`)と同一性(`is`)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`==`（二つの等号)は両辺の式の**値**が等しいときに`True`となります。\n",
    "`is` は両辺の式が同じ**オブジェクト**であるとき、`True`となります。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True False False\n"
     ]
    }
   ],
   "source": [
    "a=(1,2,3)\n",
    "b=(1,2,3)\n",
    "\n",
    "print(a == b, a is b, id(a) == id(b))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`id()`は引数に与えられたオブジェクトの　アイデンティティ(多くの場合は、オブジェクトのアドレス）を返します。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "`a`, `b` はいずれも`1,2,3`を要素とするタプルですが、別のオブジェクトです。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True True True\n"
     ]
    }
   ],
   "source": [
    "a=b=(1,2,3)\n",
    "print(a == b, a is b, id(a) == id(b))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "`a`, `b` は同じオブジェクトです。もちろんその値も一致します。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False False False\n"
     ]
    }
   ],
   "source": [
    "a=[1,2,3]\n",
    "b=(1,2,3)\n",
    "\n",
    "print(a == b, a is b, id(a) == id(b))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "リストとタプルは違う種類のオブジェクトなので、値としても異なります。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    ">  ここで質問です。\n",
    "> ``` python\n",
    "> a=100\n",
    "> b=100\n",
    "> ```\n",
    "> とした時、\n",
    "> \n",
    "> ```\n",
    "> print( a == b, a is b, id(a) == id(b))\n",
    "> ```\n",
    "> \n",
    "> はどんな結果になるでしょう？　結果を予想してから実行してみましょう。\n",
    "> 解説は次回に。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True False False\n"
     ]
    }
   ],
   "source": [
    "a=100.0\n",
    "b=100.0\n",
    "print( a == b, a is b, id(a) == id(b))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python では -5~256の整数は特別扱いされている。これらの整数はシステム初期化時に作成されたオブジェクトが使い回される。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### 比較の連鎖\n",
    "\n",
    "pythonでは　`expr1 < expr2 < expr3`のような書き方が許されています。この式は、`expr1 < expr2`かつ` expr2 < expr3`の時に限って`True`となります。\n",
    "この式は、`(expr1 < expr2) and (expr2　<　expr3)`とは異なり、\n",
    "`expr2`は***一度だけ評価*** されます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x=1/2\n",
    "0 < x < 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "## 論理演算(ブール演算）と　整数のビット毎の演算\n",
    "\n",
    "- 論理演算: `and`,　`or`, `not`\n",
    "- ビット毎の論理演算：　`&`,　`|`, `^`(exclusive or), `~` (invert)\n",
    "    -  ビットシフト演算子: `>>` , `<<`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "論理演算はC言語の場合　( `&&`, `||` , `!` ) とは異なります。　"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### 論理式の値\n",
    "\n",
    "一般の式に対して、論理演算を行った結果は、ブール値(True/False)とは限りません。　\n",
    "\n",
    "<式> `op` <式> \n",
    "\n",
    "結果の真偽を決めた式と同じタイプの型を持ちます。　　次の例をご覧ください："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.0 and 3.0 = 3.0, 2.0 or 3.0 = 2.0,\n",
      "2.0 and 0.0 = 0.0, not 2.0 = False, not 0.0 = True\n",
      " (1.0 == 0.0) and 1.0 = False, (1.0 == 0.0) or 1.0 = 1.0\n"
     ]
    }
   ],
   "source": [
    "print(\n",
    "    f\"{2.0 and 3.0 = :}, {2.0 or 3.0 = :},\\n\"\n",
    "    f\"{2.0 and 0.0 = :}, {not 2.0 = :}, {not 0.0 = :}\\n\",\n",
    "    f\"{(1.0 == 0.0) and 1.0 = :}, {(1.0 == 0.0) or 1.0 = :}\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "> 再び、 ここで質問です。\n",
    "> \n",
    "> `((r:=1) or (r:=r+2)) and (r:=r+4)`\n",
    "> \n",
    "> および\n",
    "> \n",
    "> `((r:=1) and (r:=r+2)) or (r:=r+4)`\n",
    "> \n",
    "> の結果はそれぞれ何になりますか？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "((r:=1) or (r:=r+2)) and (r:=r+4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "((r:=1) and (r:=r+2)) or (r:=r+4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "#### 整数のビット演算\n",
    "整数に対しては、　ビット毎の論理演算子：　&,　|, ^(exclusive or) , ~ (not)が使えます。\n",
    "整数同士の論理演算の結果は、先ほど見たように、整数となります。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0x0f and 0xab = ab, 0x0f or 0xab = 0f,\n",
      "0x0f and 0x00 = 00, 0x0f or 0x00 = 0f,\n",
      "not 0xab = 00, not 0x00 = 01\n"
     ]
    }
   ],
   "source": [
    "print(\n",
    "    f\"{0x0f and 0xab = :02x}, {0x0f or 0xab = :02x},\\n\"\n",
    "    f\"{0x0f and 0x00 = :02x}, {0x0f or 0x00 = :02x},\\n\"\n",
    "    f\"{not 0xab = :02x}, {not 0x00 = :02x}\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "tags": []
   },
   "source": [
    "同じデータにビットごと論理演算子を使った場合、結果は全く異なります。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0x0f & 0xab = 0b, 0x0f | 0xab = af, 0x0f ^ 0xab = a4\n",
      "0x0f & 0x00 = 00, 0x0f | 0x00 = 0f, 0x0f ^ 0x00 = 0f\n",
      "~ 0xab = -ac, ~ 0x00 = -1\n",
      "0xff & (~ 0xab )= 54, 0xff&(~ 0x00) = ff\n",
      "0xff ^    0xab  = 54, 0xff ^ 0x00  = ff\n"
     ]
    }
   ],
   "source": [
    "print(\n",
    "    f\"{0x0f & 0xab = :02x}, {0x0f | 0xab = :02x}, {0x0f ^ 0xab = :02x}\\n\"\n",
    "    f\"{0x0f & 0x00 = :02x}, {0x0f | 0x00 = :02x}, {0x0f ^ 0x00 = :02x}\\n\"\n",
    "    f\"{~ 0xab = :02x}, {~ 0x00 = :02x}\\n\"\n",
    "    f\"{0xff & (~ 0xab )= :02x}, {0xff&(~ 0x00) = :02x}\\n\" \n",
    "    f\"{0xff ^    0xab  = :02x}, {0xff ^ 0x00  = :02x}\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "notes"
    },
    "tags": []
   },
   "source": [
    "Note:\n",
    " `(~n) + n`をビット表現で考えると、　`0xffffffff=-1`になる。つまり `(~n) == -n -1 `である。\n",
    " \n",
    " 制御などでビット反転が必要な時は、`0xffffffff`などとのexclusive or(`^`)をとる方がいいでしょう。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'0xf0 & 0xff =f0, 0xf0 | 0x0f =ff, 0xf0 ^ 0xff =0f'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f\"{0xf0 & 0xff =:02x}, {0xf0 | 0x0f =:02x}, {0xf0 ^ 0xff =:02x}\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "# 高速化の手法と実行速度の測定\n",
    "\n",
    "前回定義したフィボナッチ関数と今回のフィボナッチ関数の実行速度を比べてみましょう。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "source": [
    "まずは前回使った定義を再度示します。再帰的に定義されていることから、`fibr()`と名前を変えてあります。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def fibr(n:int)->int:\n",
    "    \"\"\"\n",
    "    returns the n-th fibonacci number.\n",
    "    \"\"\"\n",
    "    if n in (0,1):\n",
    "        return 1\n",
    "    return fibr(n-1) + fibr(n-2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "source": [
    "二つの関数の結果は一致しています。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([1, 1, 2, 3, 5, 8, 13, 21, 34, 55],\n",
       " [1, 1, 2, 3, 5, 8, 13, 21, 34, 55],\n",
       " [1, 1, 2, 3, 5, 8, 13, 21, 34, 55])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[fib(i) for i in range(10)], [fibr(i) for i in range(10)],[fibl(i) for i in range(10)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "### 実行時間の測定\n",
    "ここでは簡単のために、jupyterのセルマジック　`%%timeit`を使って、プログラムの実行速度を測ってみます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19.2 µs ± 375 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit \n",
    "n=10\n",
    "fibr(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "722 ns ± 4.86 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit \n",
    "n=10\n",
    "fib(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "セルマジック`%%timeit`に変わって、ラインマジック`%timeit`も使えます。\n",
    "また、`timeit` モジュールを使って、直接に実行速度を計算することもできます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "20.1 µs ± 152 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n",
      "721 ns ± 7.86 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n",
      "7.165563750000033e-07\n"
     ]
    }
   ],
   "source": [
    "n=10\n",
    "%timeit fibr(n)\n",
    "%timeit fib(n)\n",
    "Nrep=1000000\n",
    "import timeit\n",
    "print(timeit.timeit(\"fib(n)\",\n",
    "                    setup=\"n=10\", \n",
    "                    globals=locals(),\n",
    "                    number=Nrep)/Nrep)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "579 ns ± 9.77 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit \n",
    "n=10\n",
    "fibl(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "`timeit`モジュールを使って、より詳細にしらべることもできます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((0, 1.00000000458067e-06, 7.500000052118594e-07, 6.249999984220267e-07),\n",
       " (10, 1.4160000034735276e-06, 1.7910000025267436e-06, 1.9791999996243703e-05),\n",
       " (20, 1.9169999987411757e-06, 1.666999999372365e-06, 0.0022767500000000496),\n",
       " (30, 2.750000000162345e-06, 3.4580000018991086e-06, 0.29529200000000344))"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import timeit\n",
    "\n",
    "(n:=0, \\\n",
    " timeit.timeit(\"fib(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibl(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibr(n)\", globals=locals(), number=1)),\\\n",
    "(n:=10, \\\n",
    " timeit.timeit(\"fib(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibl(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibr(n)\", globals=locals(), number=1)),\\\n",
    "(n:=20, \\\n",
    " timeit.timeit(\"fib(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibl(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibr(n)\", globals=locals(), number=1)),\\\n",
    "(n:=30, \\\n",
    " timeit.timeit(\"fib(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibl(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibr(n)\", globals=locals(), number=1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 1.0839999973200065e-06 7.49999998106432e-07 4.999999987376214e-07\n",
      "10 1.7079999992120065e-06 1.957999998580817e-06 2.0290999998451298e-05\n",
      "20 2.8340000000071086e-06 2.416999997478797e-06 0.002249958000000163\n",
      "30 3.375000005689799e-06 2.9170000033218457e-06 0.28893924999999854\n"
     ]
    }
   ],
   "source": [
    " for n in range(0,40,10):\n",
    "        print(\n",
    "            n, \n",
    "            timeit.timeit(\"fib(n)\", globals=globals(), number=1),\n",
    "            timeit.timeit(\"fibl(n)\", globals=globals(), number=1),\n",
    "            timeit.timeit(\"fibr(n)\", globals=globals(), number=1)\n",
    "        )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "## きょうのまとめ\n",
    "\n",
    "今日の講座では、以下の項目についてご説明しました。\n",
    "\n",
    "* * * *\n",
    "- python3の制御構造：`while`文\n",
    "  - `if`文,`while`文, `for`文: 制御文／制御構造\n",
    "      - `break`/`continue`/`pass`/`...`(Ellipsis)\n",
    "  - 論理式：　\n",
    "\n",
    "- 代入式\n",
    "  - 代入文との違い\n",
    "\n",
    "- 実行時間の測定：`timeit`モジュール\n",
    "* * * *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "# 付録\n",
    "\n",
    "## JIT(Just in time compiler)を使ってみる。\n",
    "pythonプログラムの工夫で実行速度を短縮することができました。さらに実行速度を短縮してくれるツールもあります。\n",
    "\n",
    "numbaはpythonプログラムをJITでコンパイルし、実行時間を大幅に短縮してくれるモジュールです。\n",
    "Pythonとは別のツール、llvmコンパイラなど、のインストールが必要です。\n",
    "Pythonの高速化にはこの他にもcythonなどのツールが存在しています。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "source": [
    "ここでは、フィボナッチ関数を高速化してみます。　numbaのjitモジュールを使います。\n",
    "`@jit`はpythonのデコレーターという機能で、定義された関数に前処理を付け加えることができます。ここでは前処理として、pythonの関数をnumba.jitでコンパイルして、\n",
    "機械語バージョンの関数を使って関数を評価します。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numba \n",
    "from numba import jit\n",
    "import random\n",
    "\n",
    "@jit(nopython=True)\n",
    "def fibn(n:int)->int:\n",
    "    if n in (0, 1):\n",
    "        return numba.longlong(1)\n",
    "    a=b=numba.longlong(1)\n",
    "    while (n := n-1 ) > 0:\n",
    "        a, b = b, a+b\n",
    "        if (b < 0):\n",
    "            raise ValueError(\"Negative result\")\n",
    "    return b\n",
    "fibn(0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最後の行で、`fibn()`は機械語にコンパイルされ、以降は`fibn()`の評価にこの機械語プログラムが使われます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55] \n",
      " [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]\n"
     ]
    }
   ],
   "source": [
    "print(\n",
    "    [fib(i) for i in range(10)],\"\\n\",\n",
    "    [fibn(i) for i in range(10)],\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "結果は同じになっているようなので、実行速度を測ってみます。\n",
    "\n",
    "`%%timeit`はjupyterのセルマジックの一つで、timeitモジュールをつかって、セルの実行時間を測定します。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.98 µs ± 53.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "n=40\n",
    "fib(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "171 ns ± 0.882 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "n=40\n",
    "fibn(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "と大幅に改善されています。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "しかし、別の極端な場合(n=0)をみると、jit版の方が時間がかかっています。\n",
    "機械語のプログラムの呼び出し、戻り値のPythonへの変換などのオーバーヘッドがあるためと考えられます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "85.1 ns ± 1.38 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "n=0\n",
    "fib(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "137 ns ± 1.39 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "n=0\n",
    "fibn(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "source": [
    "これら二つの関数は, n=91までは同じ値を返します。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([(90, 4660046610375530309), (91, 7540113804746346429)],\n",
       " [(90, 4660046610375530309), (91, 7540113804746346429)])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[(i,fib(i)) for i in range(90,92,1)], [(i,fibn(i)) for i in range(90,92,1)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "しかし、`n=92`の場合を計算してみると、"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib(92)=12200160415121876738\n",
      "Error! Negative result\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    print(f\"{fib(92)=:}\")\n",
    "    print(f\"{fibn(92)=:}\")\n",
    "except ValueError as m:\n",
    "    print(\"Error!\",m)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "と`fibn`はエラーになってしまいます。これは、python3の整数に上限はありませんが、numbaでコンパイルされた関数の`fibn`中では、オーバーフローにより、正であるべき変数が負になったためです。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "0x7fffffffffffffff > (4660046610375530309 + 7540113804746346429)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "jitでコンパイルされる関数でuint64=ulonglongとして、エラーを回避できるか試してみましょう。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "@jit(nopython=True)\n",
    "def fibln(n:int)->int:\n",
    "    if n in (0, 1):\n",
    "        return numba.uint64(1)\n",
    "    a=b=numba.uint64(1)\n",
    "    for i in range(1,n):\n",
    "        a, b = b, a+b\n",
    "        if (b < 0):\n",
    "            raise ValueError\n",
    "    return b\n",
    "fibln(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(12200160415121876738, 12200160415121876738)"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fibln(92),fib(92)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "とn=92に対しては、正しいあたいがもとまりました。ところが、n=93については、"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1293530146158671551, 19740274219868223167)"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fibln(93),fib(93)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "と異なった値が出てきます。これは結果を16進表示してわかるように、結果がuint64で表現できる最大の値をこえているためです。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('fib(93) =0111f38ad0840bf6bf', 'fibln(93) =0011f38ad0840bf6bf')"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f\"{fib(93) =:018x}\",f\"{fibln(93) =:018x}\","
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "いくら高速でもこれでは困ります。 整数を諦めて、　結果を浮動小数点で求めることもできます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.0"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "@jit(nopython=True)\n",
    "def fibfn(n:int)->int:\n",
    "    if n in (0, 1):\n",
    "        return numba.uint64(1)\n",
    "    a=b=numba.float64(1)\n",
    "    for i in range(1,n):\n",
    "        a, b = b, a+b\n",
    "        if (b < 0):\n",
    "            raise ValueError\n",
    "    return b\n",
    "fibfn(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([(90, 4.66004661037553e+18),\n",
       "  (91, 7.540113804746346e+18),\n",
       "  (92, 1.2200160415121877e+19),\n",
       "  (93, 1.9740274219868226e+19)],\n",
       " [(90, 4660046610375530309),\n",
       "  (91, 7540113804746346429),\n",
       "  (92, 12200160415121876738),\n",
       "  (93, 19740274219868223167)])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[(i,fibfn(i)) for i in range(90,94,1)], [(i,fib(i)) for i in range(90,94,1)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "これでとりあえずは結果が真の値から大きくずれてしまうことはありません。(float64の精度範囲で一致）\n",
    "しかし、　n>1475ではfloat64の表現できる数値を超えてしまいます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(130698922376339931803631155380271983098392443907412640726006659460192793070479231740288681087777017721095463154979012276234322246936939647185366706368489362660844147449941348462800922755818969634743348982916424954062744135969865615407276492410653721774590669544801490837649161732095972658064630033793347171632,\n",
       " 1.3069892237633987e+308,\n",
       " 211475298697902185255785861961179135570552502746803252174956226558634024323947666637137823932524397611864671566211908330263377425204552074188208686993669123754004340250943108709212299180422293009765404930508242975773774612140021599477983006713536106549441161323499077298115887067363710153036315849480388057657,\n",
       " inf)"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib(1475),fibfn(1475), fib(1476), fibfn(1476)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((0, 9.160000047359063e-07, 5.332999990059761e-06),\n",
       " (3, 1.167000007740171e-06, 7.49999998106432e-07),\n",
       " (30, 2.708000010898104e-06, 7.090000053722179e-07),\n",
       " (91, 7.457999998905507e-06, 6.249999984220267e-07))"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import timeit\n",
    "(n:=0, \\\n",
    " timeit.timeit(\"fib(n)\", globals=globals(), number=1),\\\n",
    " timeit.timeit(\"fibn(n)\", globals=globals(), number=1)),\\\n",
    "(n:=3,\\\n",
    " timeit.timeit(\"fib(n)\", globals=globals(), number=1),\\\n",
    " timeit.timeit(\"fibn(n)\", globals=globals(), number=1)),\\\n",
    "(n:=30,\\\n",
    " timeit.timeit(\"fib(n)\", globals=globals(), number=1),\\\n",
    " timeit.timeit(\"fibn(n)\", globals=globals(), number=1)),\\\n",
    "(n:=91,\\\n",
    " timeit.timeit(\"fib(n)\", globals=globals(), number=1),\\\n",
    " timeit.timeit(\"fibn(n)\", globals=globals(), number=1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 1)"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "@jit(nopython=False)\n",
    "def fibrn(n:int)->int:\n",
    "    if n == 0 or n == 1:\n",
    "        return numba.int64(1)\n",
    "    return fibrn(n-1) + fibrn(n-2)\n",
    "fibrn(0),fibr(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0,\n",
       " 1.1669999935293163e-06,\n",
       " 5.166999997641142e-06,\n",
       " 7.919999944761003e-07,\n",
       " 1.7499999955816747e-06,\n",
       " 8.749999977908374e-07,\n",
       " 1.834000002531866e-06)"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(n:=0, \n",
    " timeit.timeit(\"fibr(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibrn(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fib(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibn(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibl(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibln(n)\", globals=locals(), number=1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(34,\n",
       " 1.9238507079999891,\n",
       " 0.04720058399999516,\n",
       " 5.458000003955021e-06,\n",
       " 2.250000008530151e-06)"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(n:=34, \n",
    " timeit.timeit(\"fibr(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibrn(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fib(n)\", globals=locals(), number=1),\\\n",
    " timeit.timeit(\"fibn(n)\", globals=locals(), number=1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 6.279199999426055e-05\n",
      "2 0.00012150000000588079\n",
      "5 0.00029895900000553866\n",
      "10 0.0005972499999984393\n",
      "20 0.0011201249999999163\n",
      "50 0.0027729580000084297\n",
      "100 0.005542207999994275\n",
      "200 0.012367707999999311\n",
      "500 0.028814584000002696\n",
      "1000 0.056347207999991156\n",
      "2000 0.11250199999999211\n",
      "5000 0.2801979590000059\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(5000, 0.2801979590000059)"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "timeit.Timer(\"(fibrn(20))\", globals=locals()).autorange(lambda number, time_taken:print(number, time_taken))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(5.666999996378763e-06,\n",
       " 1.3749999965284587e-06,\n",
       " 5.59160000079828e-05,\n",
       " 0.007095250000006104,\n",
       " 0.07875716700000623,\n",
       " 1.0202988329999982,\n",
       " 7.170110916999988)"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "timeit.timeit(\"(fibrn(0))\", globals=locals(), number=1),\\\n",
    "timeit.timeit(\"(fibrn(10))\", globals=locals(), number=1),\\\n",
    "timeit.timeit(\"(fibrn(20))\", globals=locals(), number=1),\\\n",
    "timeit.timeit(\"(fibrn(30))\", globals=locals(), number=1),\\\n",
    "timeit.timeit(\"(fibrn(35))\", globals=locals(), number=1),\\\n",
    "timeit.timeit(\"(fibrn(40))\", globals=locals(), number=1),\\\n",
    "timeit.timeit(\"(fibrn(43))\", globals=locals(), number=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1.3340000037942445e-06,\n",
       " 1.9999999992137418e-05,\n",
       " 0.0022419999999954143,\n",
       " 0.2828014999999908,\n",
       " 3.0749212500000027)"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "timeit.timeit(\"(fibr(0))\", globals=locals(), number=1),\\\n",
    "timeit.timeit(\"(fibr(10))\", globals=locals(), number=1),\\\n",
    "timeit.timeit(\"(fibr(20))\", globals=locals(), number=1),\\\n",
    "timeit.timeit(\"(fibr(30))\", globals=locals(), number=1),\\\n",
    "timeit.timeit(\"(fibr(35))\", globals=locals(), number=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 5 µs, sys: 1e+03 ns, total: 6 µs\n",
      "Wall time: 7.87 µs\n",
      "2.55 µs ± 32.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n",
      "690 ns ± 5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%time fib(35)\n",
    "%timeit fib(35)\n",
    "%timeit fib(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.47 µs ± 8.91 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit fib(20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "@jit(nopython=False)\n",
    "def foo(n:int)->int:\n",
    "    return numba.int64(n)\n",
    "v=foo(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4.708000005848589e-06"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "timeit.timeit(\"(foo(20))\", globals=globals(), number=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    },
    "tags": []
   },
   "source": [
    "# 関数実行プロファイルをチェックする\n",
    "プログラムの動作を理解する上で、関数実行プロファイルも役に立つ情報の一つです。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cProfile"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "         2692540 function calls (4 primitive calls) in 0.505 seconds\n",
      "\n",
      "   Ordered by: standard name\n",
      "\n",
      "   ncalls  tottime  percall  cumtime  percall filename:lineno(function)\n",
      "2692537/1    0.505    0.000    0.505    0.505 968652943.py:1(fibr)\n",
      "        1    0.000    0.000    0.505    0.505 <string>:1(<module>)\n",
      "        1    0.000    0.000    0.505    0.505 {built-in method builtins.exec}\n",
      "        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "cProfile.run(\"fibr(30)\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2692537.0"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "@jit(nopython=True)\n",
    "def Nfib(n:int)->int:\n",
    "    if n in (0, 1):\n",
    "        return numba.ulonglong(1)\n",
    "    a=b=numba.ulonglong(1)\n",
    "    while (n := n-1 ) > 0:\n",
    "        a, b = b, a+b+1\n",
    "        if (b < 0):\n",
    "            raise ValueError\n",
    "    return b\n",
    "import math\n",
    "Nfib(30)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "         4 function calls in 0.000 seconds\n",
      "\n",
      "   Ordered by: standard name\n",
      "\n",
      "   ncalls  tottime  percall  cumtime  percall filename:lineno(function)\n",
      "        1    0.000    0.000    0.000    0.000 2970711770.py:5(fibn)\n",
      "        1    0.000    0.000    0.000    0.000 <string>:1(<module>)\n",
      "        1    0.000    0.000    0.000    0.000 {built-in method builtins.exec}\n",
      "        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "cProfile.run(\"fibn(91)\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "         4 function calls in 0.843 seconds\n",
      "\n",
      "   Ordered by: standard name\n",
      "\n",
      "   ncalls  tottime  percall  cumtime  percall filename:lineno(function)\n",
      "        1    0.843    0.843    0.843    0.843 2759940478.py:1(fibrn)\n",
      "        1    0.000    0.000    0.843    0.843 <string>:1(<module>)\n",
      "        1    0.000    0.000    0.843    0.843 {built-in method builtins.exec}\n",
      "        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "cProfile.run(\"fibrn(40)\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "toc-autonumbering": true,
  "toc-showcode": false,
  "toc-showmarkdowntxt": false,
  "toc-showtags": false
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
