{ "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 \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": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'0b1010'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bin(10)" ] }, { "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": { "collapsed": true, "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": { "collapsed": true, "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": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.5\n" ] }, { "data": { "text/plain": [ "1.5" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = [0 ,0,0,0,1, 1,0,0]\n", "sign = -1 if v[0] == -1 else 1\n", "value = v[1]*2**3\n", "value += v[2]*2**2\n", "value += v[3]*2**1\n", "value += v[4]*2**0\n", "\n", "value += v[5]*2**(-1)\n", "value += v[6]*2**(-2)\n", "value += v[7]*2**(-3)\n", "\n", "print(sign*value)\n", "[(i,4-i) for i in range(1,8)]\n", "[v[i]*2**(4-i)for i in range(1,8)]\n", "sum([v[i]*2**(4-i)for i in range(1,8)])" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.375\n" ] } ], "source": [ "def value(v,p,n):\n", " sign = -1 if v[0] == 1 else 1\n", " \n", " return sign*sum([v[i]*2**(p-i)for i in range(1,(p+n+1))])\n", "\n", " \n", "v = [0, 0,0,0,1, 0,1,1]\n", "\n", "print( value(v,4,3) )" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.375\n" ] } ], "source": [ " \n", "v = [0, 0,0,0,1, 0,1,1]\n", "\n", "print( value(v,4,3) )\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": "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.6.1" } }, "nbformat": 4, "nbformat_minor": 1 }