{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# บทที่ 1 ตัวเลขและการวิเคราะห์ความคลาดเคลื่อน\n",
    "\n",
    "> Mathematically correct programming bug is **hard** to spot.\n",
    "\n",
    "> สมการถูกแต่...โปรแกรมผิด\n",
    "\n",
    ">> Paulgramming - 2017\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# ตัวเลขและความคลาดเคลื่อนในโปรแกรม\n",
    "## C++\n",
    "\n",
    "```c++\n",
    "#include <iostream>\n",
    "using namespace std;\n",
    "main() {\n",
    "  float x = 1.0;    \n",
    "  float y = x / 3.0;\n",
    "  cout << ((x == y * 3.0)?\"\": \"Not\") << \" Equal\" << endl;\n",
    "}\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# ตัวเลขและความคลาดเคลื่อนในโปรแกรม\n",
    "## Java\n",
    "\n",
    "```java\n",
    "public class Test {\n",
    "  public static void main(String[] a) {\n",
    "    float x = 1.0;\n",
    "    float y = x / 3.0;\n",
    "    System.out.println( ((x == y * 3.0)?\"\": \"Not\") + \" Equal\" );\n",
    "  }\n",
    "}\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# ตัวเลขและความคลาดเคลื่อนในโปรแกรม\n",
    "## Python\n",
    "\n",
    "```python\n",
    "x = 1.0\n",
    "y = x / 3.0\n",
    "print(\"Equal\" if x == y*3.0 else \"Not Equal\")\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "# มีหลายตัวเลขที่ไม่\n",
    "x = 1.0\n",
    "y = x / 3.0\n",
    "#print(\"Equal\" if x == y*3.0 else \"Not Equal\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# มีหลายตัวเลขที่คอมเก็บค่าไ่ม่ได้\n",
    "\n",
    "* ตัวเลขที่คอมพิวเตอร์ต้องประมาณการ (Inexact numbers)\n",
    "    * ค่าอตรรกยะ (irrational numbers) $\\pi, \\e, ...$\n",
    "    * ค่าตรรกยะ (rational numbers) ที่ไม่สามารถแปลงเป็นเลขฐานสองได้\n",
    "```python\n",
    "0.1 + 0.2 == 0.3\n",
    "```\n",
    "\n",
    "* ตัวเลขที่คอมพิวเตอร์สามารถเก็บค่าได้ตรง (Exact numbers)\n",
    "> ตัวเลขที่สามารถแปลงให้เป็นเลขฐานสองได้"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Floating-Point Binary\n",
    "\n",
    "> ตัวเลข(number) เขียนแทนด้วยสายของเลขเดี่ยว(digit) โดยจำนวนของเลขเดี่ยว ขึ้นอยู่กับ เลขฐาน(base)\n",
    "\n",
    "ในระบบจำนวนนับของคนเราจะเป็นเลขฐาน 10 โดยมี digit ที่ใช้ได้ได้แก่ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9\n",
    "ยกตัวอย่างตัวเลขในเลขฐาน 10 เช่น  128  77  12100  เป็นต้น\n",
    "\n",
    "ตัวเลขที่ใช้ในคอมพิวเตอร์จะเป็นเลขฐาน 2 โดยมี digit ที่ใช้ได้ ได้แก่ 0 และ 1 \n",
    "ยกตัวอย่างตัวเลขในเลขฐาน 2 เช่น  1, 101, 1101  เป็นต้น"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Terminology\n",
    "** Bit **\n",
    ": 0 or 1\n",
    "\n",
    "** Byte ** \n",
    ": 8 bits\n",
    "\n",
    "** Real **\n",
    ": 4 bytes **single precision**\n",
    ": 8 bytes **double precision**\n",
    "\n",
    "** Integer **\n",
    ": 1, 2, 4, or 8 byte signed\n",
    ": 1, 2, 4, or 8 byte unsigned\n",
    "\n",
    "> ขึ้นอยู่กับภาษาโปรแกรมว่าจะใช้สายที่มีความยาวเท่าไหร่ 8, 16, 32 หรือ 64 เป็นต้น\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# ข้อตกลง\n",
    "\n",
    "* เพื่อง่ายต่อการคำนวณเราจะใช้สายที่มีความยาว 8 และเขียนแยกเป็นกลุ่มละ 4 เพื่อง่ายต่อการคำนวน \n",
    "\n",
    "> เช่น  1 = 0000 0001\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Binary $\\rightarrow$ Integer\n",
    "\n",
    "|      |      |      |      |      |      |      |      |\n",
    "|------|------|------|------|------|------|------|------|\n",
    "|   1  |   1  |   1  |   0  |   0  |   1  |   1  |   1  |\n",
    "|$2^7$ |$2^6$ |$2^5$ |$2^4$ |$2^3$ |$2^2$ |$2^1$ |$2^0$ |\n",
    "\n",
    "$1\\times2^7 + 1\\times2^6 + 1\\times2^5 + 0\\times2^4 + 0\\times2^3 + 1\\times2^2 + 1\\times2^1 + 1\\times2^0$\n",
    "\n",
    "$1\\times 128+ 1\\times 64 + 1\\times 32 + 0\\times 16 + 0\\times 8 + 1\\times 4 + 1\\times 2 + 1 \\times 1$\n",
    "\n",
    "\n",
    "$128 + 64 + 32 + 0 + 0 + 4 + 2 + 1$\n",
    "\n",
    "**Answer**\n",
    "> $231$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# เขียนโปรแกรมทดสอบ\n",
    "\n",
    "* คำนวณหาผลลัพธ์\n",
    "```python\n",
    "1*2**7 + 1*2**6 + 1*2**5 + 0*2**4 + 0*2**3 + 1*2**2 + 1*2**1 + 1*2**0\n",
    "```\n",
    "\n",
    "* คำสั่งแปลงเลขฐานต่างๆ\n",
    "```python\n",
    "int('11100111', 2)  # แปลง str '11100111' ฐาน 2 เป็น int\n",
    "oct(35)             # แปลง 35 ฐานสิบ ให้เป็นฐาน 8\n",
    "hex(35)             # แปลง 35 ฐานสิบ ให้เป็นฐาน 16\n",
    "bin(35)             # แปลง 35 ฐานสิบ ให้เป็นฐาน 2\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "#int('11100111', 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "#### Exercise\n",
    "จงแสดงการแปลงตัวเลขฐานสองต่อไปนี้เป็นจำนวนเต็ม\n",
    "* 10011001\n",
    "* 00010011\n",
    "* 00011111"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### Binary $\\rightarrow$ Float\n",
    "กำหนดตำแหน่งที่เลขสองกำลังเป็นศูนย์ (fix-point representation)\n",
    "\n",
    "|      |      |      |      |      |      |      |      |\n",
    "|------|------|------|------|------|------|------|------|\n",
    "|   1  |   1  |   1  |   0  |   0  |   1  |   1  |   1  |\n",
    "|$2^5$ |$2^4$ |$2^3$ |$2^2$ |$2^1$ |$2^0$ |$2^-1$ |$2^-2$ |\n",
    "\n",
    "$1\\times 2^5+1\\times 2^4+1\\times 2^3+0\\times 2^2+9\\times 2^1+1\\times 2^0+1\\times 2^{-1}+1\\times 2^{-2}$\n",
    "\n",
    "$1\\times2^5 + 1\\times2^4 + 1\\times2^3 +0\\times 2^2+0\\times2^1+1\\times 1+\\frac{1}{2}+\\frac{1}{4}$\n",
    "\n",
    "$32 + 16 + 8 + 0 + 0 + 1 + 0.5 + 0.25$\n",
    "\n",
    "**Answer**\n",
    "> 57.75"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "#1*2**5 + 1*2**4 + 1*2**3 + 0*2**2 + 0*2**1 + 1*2**0 + 1*2**(-1) + 1*2**(-2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "#### Binary Fixed-Point Arithmetic\n",
    "|      |      |      |      |      |      |      |      |      |\n",
    "|------|------|------|------|------|------|------|------|------|\n",
    "|   1  |   1  |   1  | ...  |   0  |  0  |   ...  |   1  |   1  |\n",
    "| sign ||$2^{m-1}$ |$2^{m-2}$ | ... |$2^0$ |$2^{-1}$ | ... |$2^{-n+1}$ |$2^{-n}$ |\n",
    "\n",
    "* Parameters: $m, n \\in Z$\n",
    "* $m$ ความยาวของสาย(จำนวน bit) ที่ใช้เป็นจำนวนเต็ม(integer portion)\n",
    "* $n$ ความยาวของสาย(จำนวน bit) ที่ใช้เป็นตัวหาร(fractional portion)\n",
    "* ความยาวทั้งหมดของสายเป็น $m+n+1$ รวมกับ bit ที่ใช้บอกเครื่องหมาย (+/-)\n",
    "* ความรู้เพิ่มเติม: [Fixed-Point Numbers](https://en.wikibooks.org/wiki/Floating_Point/Fixed-Point_Numbers)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Error in Binary Fixed-Point Arithmetic\n",
    "\n",
    "** สมมติว่ามีแค่ 2 bit ให้ใช้ ** \n",
    "\n",
    "> $m = 1, n=1$ โดยที่ไม่คิด sign bit\n",
    "\n",
    "$0.1 \\times 0.1 = 0.01 \\approx 0.0$ \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Binary Floating-Point Arithmetic\n",
    "1. IEEE single precision format\n",
    "\n",
    "|  0   |     1-8       |       9-31        |\n",
    "|:----:|:-------------:|:-----------------:|\n",
    "| $s$  |      $e$      |        $f$        |\n",
    "| $0$  |   $00001001$  |   $0011011...01$  |\n",
    "\n",
    "$ = (-1)^s \\times 2^{e-127} \\times 1.f $\n",
    "\n",
    "โดยที่\n",
    " * **sign** $s \\in {0, 1}$\n",
    " * **biased exponent** $0 \\le e \\le 255$\n",
    " * **exponent** $p=e-127$ so $-126 \\le p \\le 127$\n",
    " * **significand** $1.f$ "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, -1)"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(-1)**0,(-1)**1\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Binary Floating-Point Arithmetic \n",
    "2. IEEE double precision format\n",
    "\n",
    "|  0   |     1-11      |       12-63       |\n",
    "|:----:|:-------------:|:-----------------:|\n",
    "| $s$  |      $e$      |        $f$        |\n",
    "| $0$  | $00001000111$ |   $0011011...01$  |\n",
    "\n",
    "$ = (-1)^s \\times 2^{e-1023} \\times 1.f $\n",
    "\n",
    "โดยที่\n",
    " * **sign** $s \\in {0, 1}$\n",
    " * **biased exponent** $0 \\le e \\le 2047$\n",
    " * **exponent** $p=e-1023$ so $-1022 \\le p \\le 1024$\n",
    " * **significand** $x = 1.f$ "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Example \n",
    "\n",
    "จงเขียนคำสั่งเพื่อหาค่าของตัวเลขตามข้อต่อกำหนดต่อไปนี้ โดยใช้ IEEE single precision format\n",
    "> 0 1111 0000 0000 1010 0000 0000 0000 000\n",
    " \n",
    "**Answer** \n",
    "หาค่า $s, e, f$ จากโจทย์\n",
    "> $s = 0$\n",
    "\n",
    "> $e$ = 11110000\n",
    "\n",
    "> $f$ = 0000101 \n",
    "\n",
    "```python\n",
    "s = 0\n",
    "e = int('11110000', 2)\n",
    "x = 1 + 0*2**(-1) + 0*2**(-2) + 0*2**(-3) + 0*2**(-4) + 1*2**(-5) + 0*2**(-6) + 1*2**(-7)\n",
    "print( (-1)**s * 2**(e-127) * x )\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Exercise \n",
    "1. จงเขียนคำสั่งเพื่อหาค่าของตัวเลขตามข้อต่อกำหนดต่อไปนี้ โดยใช้ IEEE single precision format\n",
    " * $s = 0$\n",
    " * $e$ = 1111 0000 0000\n",
    " * $f$ = 0000 1010 \n",
    " \n",
    "2. จงเขียนคำสั่งเพื่อหาค่าของตัวเลขตามข้อต่อกำหนดต่อไปนี้ โดยใช้ IEEE double precision format\n",
    " * $s = 1$\n",
    " * $e$ = 0000 0011 0000\n",
    " * $f$ = 0110 1010 \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Error Calculation\n",
    "\n",
    "* **Absolute Error** \n",
    "    $\\rightarrow E_{abs} = \\| x_0 - x \\|$\n",
    "* **Relative Error**\n",
    "    $\\rightarrow E_{rel} = \\frac { E_{abs} }{x} $\n",
    "* **Percentage Error**\n",
    "    $\\rightarrow E_{per} = E_{rel} \\times 100$"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "celltoolbar": "Slideshow",
  "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.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}