Skip to content

Instantly share code, notes, and snippets.

@teruo41
Created June 20, 2023 07:43
Show Gist options
  • Save teruo41/9501c69c2731c5bcecb77844034d4554 to your computer and use it in GitHub Desktop.
Save teruo41/9501c69c2731c5bcecb77844034d4554 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "76976a82-56b7-4fbb-bd8d-7af94a36ec43",
"metadata": {},
"source": [
"# Computer Architecture I - floating point"
]
},
{
"cell_type": "markdown",
"id": "d9605eaf-4daf-4931-a3ee-18e3f6bf33aa",
"metadata": {},
"source": [
"## Python environment check"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "0e66d489-c981-4257-b98f-9ebf27714e21",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3.10.9 (main, Jan 11 2023, 15:21:40) [GCC 11.2.0]\n"
]
}
],
"source": [
"import sys;\n",
"print(sys.version)"
]
},
{
"cell_type": "markdown",
"id": "a3bd2d33-a9d2-4604-819a-66b9b5aae5f7",
"metadata": {},
"source": [
"## Class definition for floating point representation (myfloat8)\n",
"\n",
"### Step 1: myfloat8 の理解\n",
"myfloat8 は、浮動小数点数を bool 値の配列で表現する class として実装されています。\n",
"それらは、`sig`(符号)、`shisubu`(指数部)、`kasubu`(仮数部)からなっています。\n",
"myfloat8 は、8ビット浮動小数点数で、sig, shisubu, kasubu はそれぞれ 1, 3, 4 ビットです。\n",
"\n",
"まずは以下の部分を読んで理解してみましょう。\n",
"- `__init__()` の # encode 以下のブロック\n",
"- tonum() 自体と、呼び出されている関数たち\n",
"\n",
"`__repr()__` は、class のインスタンスを print() した際、出力する文字列を生成するために使われる予約済の関数です。\n",
"\n",
"### Step 2: encode と decode を試す\n",
"それができたら、セル3~10を参考に、書き換えていろいろ試してみてください。\n",
"浮動小数点数の桁数不足によって、量子化誤差が生じることに注意してください。\n",
"\n",
"### Step 3: 和と積の実装を考えてみる\n",
"`__add__()` と `__mul__()` は class のインスタンスをそれぞれ `+` と `*` の演算子でつないだ時に呼ばれる関数です。\n",
"\n",
"セル2に実装されている myfloat8 では、`__add__()` と `__mul__()` の実装は不完全です。\n",
"\n",
"講義内容に沿って、ビットレベルの操作を記述してみましょう。\n",
"浮動小数点数の演算手順への理解が深まるはずです。\n",
"\n",
"演算子の挙動を指定する関数の記述を見慣れない人もいるかもしれません。\n",
"たとえば、myfloat8 のインスタンス a と b があったとき、 `a + b` は、`a.__add__(b)` を呼び出します。\n",
"myfloat8 では `__add__(self, other)` として定義されていますが、この時、`self = a, other = b` として実行されます。\n",
"今回の場合、`__add__()` や `__mul__()` は myfloat8 のインスタンスを返すべきであることに注意してください。\n",
"\n",
"### 注意とお願い\n",
"- 実はまだ、`__add__()` と `__mul__()` の模範解答はありません。なので、実装に挑戦する人は、うまく作成できたら谷本にその実装をぜひ共有してください。\n",
"- それ以外の部分についても、間違っている箇所(バグ)があるかもしれません。おかしいと思うところを見つけた場合も、谷本に教えてくれると助かります。"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "78fffb09-efc2-4bcc-b212-bb46d7a63312",
"metadata": {},
"outputs": [],
"source": [
"class myfloat8:\n",
" nshisubu = 3\n",
" nkasubu = 4\n",
" shisuoff = 2 ** (nshisubu - 1) - 1\n",
" \n",
" sig: bool\n",
" shisubu: list[bool]\n",
" kasubu: list[bool]\n",
" \n",
" def __init__(self, f:float=None, li:list[bool]=None):\n",
" ns = self.nshisubu\n",
" nk = self.nkasubu\n",
" so = self.shisuoff\n",
" i2l = self.inttolist\n",
" \n",
" if f == None and li == None:\n",
" self.sig = bool(0)\n",
" self.shisubu = [bool(0) for i in range(ns)]\n",
" self.kasubu = [bool(0) for i in range(nk)]\n",
" \n",
" if f != None and li != None:\n",
" print(\"Error.\")\n",
" return\n",
" \n",
" # encode\n",
" if f != None:\n",
" self.sig = False if f >= 0 else True\n",
" f = f if f > 0 else f * (-1)\n",
"\n",
" cnt = 0\n",
" if f >= 2:\n",
" while f >= 2 and cnt <= so:\n",
" cnt += 1\n",
" f /= 2\n",
" elif f < 2 and f >= 1:\n",
" pass\n",
" elif f < 1 and f > 0:\n",
" while f < 1 and cnt >= 1 - so:\n",
" cnt -= 1\n",
" f *= 2\n",
" else: # f == 0\n",
" cnt -= so\n",
" self.shisubu = i2l(cnt+so, ns)\n",
" self.kasubu = i2l(int(f*(2**nk)), nk+1)[1:nk+1]\n",
"\n",
" if li != None:\n",
" self.sig = li[0]\n",
" self.shisubu = li[1:ns+1]\n",
" self.kasubu = li[ns+1:ns+nk+1]\n",
"\n",
" # utility\n",
" def mystr(self, x:bool):\n",
" return '1' if x else '0'\n",
" \n",
" # utility\n",
" def tobit(self, x:bool):\n",
" return 1 if x else 0\n",
" \n",
" # utility\n",
" def inttolist(self, x:int, c:int):\n",
" ret = list()\n",
" ret.extend([bool(int((x/(2**i))%2)) for i in range(c)])\n",
" ret.reverse()\n",
" return ret\n",
" \n",
" # decode\n",
" def getshisu(self) -> int:\n",
" ns = self.nshisubu\n",
" sh = self.shisubu\n",
" so = self.shisuoff\n",
" tb = self.tobit\n",
" en = enumerate\n",
" return sum([2**(ns-y-1) * tb(x) for (y,x) in en(sh)]) - so\n",
" \n",
" # decode\n",
" def getkasu(self) -> float:\n",
" ka = self.kasubu\n",
" so = self.shisuoff\n",
" tb = self.tobit\n",
" en = enumerate\n",
" _sh = self.getshisu()\n",
" _ka_t = sum([(0.5)**(y+1) * tb(x) for (y,x) in en(ka)])\n",
" return 1 + _ka_t if _sh+so else _ka_t\n",
"\n",
" # decode\n",
" def tonum(self) -> float:\n",
" _si: int = -1 if self.sig else 1\n",
" _sh: int = self.getshisu()\n",
" _ka: float = self.getkasu()\n",
" return _si * (2 ** _sh) * _ka\n",
" \n",
" def fulladder(self, a:bool, b:bool, c0:bool):\n",
" c1: bool = (a and b) or (b and c0) or (c0 and a)\n",
" t1: bool = ((not a) and (not b) and c0) or ((not a) and b and (not c0))\n",
" t2: bool = (a and (not b) and (not c0)) or (a and b and c0)\n",
" s: bool = t1 or t2\n",
" return (c1, s)\n",
" \n",
" def binadd(self, a:list[bool], b:list[bool], n:int):\n",
" s: list[bool] = [False for i in range(n+1)]\n",
" for i in range(n):\n",
" (_c, _s) = self.fulladder(a[i], b[i], s[i+1])\n",
" s[i] = _s\n",
" s[i+1] = _c\n",
" return (s[0:n], s[n])\n",
" \n",
" def binminus(self, a:list[bool]):\n",
" li: list[bool] = [not a[i] for i in range(len(a))]\n",
" t: list[bool] = [0 for i in range(len(a))]\n",
" t[0] = True\n",
" return self.binadd(li, t, len(a))[0]\n",
" \n",
" def __repr__(self) -> str:\n",
" si = self.sig\n",
" sh = self.getshisu()\n",
" ka = self.getkasu()\n",
" so = self.shisuoff\n",
" ms = self.mystr\n",
" ret = ms(self.sig)\n",
" ret += ''.join([ms(x) for x in self.shisubu])\n",
" ret += ''.join([ms(x) for x in self.kasubu])\n",
" ret += \"\\n = (-1)**[{}]\".format(ms(si))\n",
" ret += \" * 2**\"\n",
" for i in range(self.nshisubu):\n",
" ret += \"[{}]\".format(ms(self.shisubu[i]))\n",
" ret += \" * \"\n",
" if self.getshisu() + so == 0:\n",
" ret += \"[{}].\".format(ms(self.kasubu[0]))\n",
" else:\n",
" ret += \"[1].[{}]\".format(ms(self.kasubu[0]))\n",
" for i in range(1, self.nkasubu):\n",
" ret += \"[{}]\".format(ms(self.kasubu[i]))\n",
" if self.getshisu() + so:\n",
" ret += \"\\n = (-1)**{} * 2**({}) * ({})\".format(ms(si), sh, ka)\n",
" ret += \"\\n = {}\".format(self.tonum())\n",
" return ret\n",
" \n",
" def __add__(self, other):\n",
" ssh = self.getshisu()\n",
" ska = self.getkasu()\n",
" osh = other.getshisu()\n",
" oka = other.getkasu()\n",
" ret = {}\n",
"\n",
" if self.sig == other.sig:\n",
" ret['sig'] = self.sig\n",
" elif ssh > osh:\n",
" ret['sig'] = self.sig\n",
" elif ssh < osh:\n",
" ret['sig'] = other.sig\n",
" else: # ssh == osh\n",
" if ska >= oka:\n",
" ret['sig'] = self.sig\n",
" else: # ska < oka\n",
" ret['sig'] = other.sig\n",
" print(\"Currently ``__add__'' is not completely implemented.\")\n",
" # li = [ret['sig']]\n",
" # li.extend([bool(0) for i in range(self.nshisubu)])\n",
" # li.extend([bool(0) for i in range(self.nkasubu)])\n",
" # print(li)\n",
" # return myfloat8(li=li)\n",
" return self\n",
" \n",
" def __mul__(self, other):\n",
" print(\"Currently ``__mul__'' is not implemented.\")\n",
" # Let's implement multiply operation\n",
" return self\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "6fe89ec8-3abe-49dd-ac76-bf8dcf1c3b30",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"00000000\n",
" = (-1)**[0] * 2**[0][0][0] * [0].[0][0][0]\n",
" = 0.0\n"
]
}
],
"source": [
"a = myfloat8()\n",
"print(a)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "1fab02e9-32b5-4352-a420-167149b08b35",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"00010000\n",
" = (-1)**[0] * 2**[0][0][1] * [1].[0][0][0][0]\n",
" = (-1)**0 * 2**(-2) * (1.0)\n",
" = 0.25\n"
]
}
],
"source": [
"a = myfloat8(li=[0,0,0,1,0,0,0,0])\n",
"print(a)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "0d823af2-f7c7-4bde-a1b1-6b22ca87b3a5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"00111000\n",
" = (-1)**[0] * 2**[0][1][1] * [1].[1][0][0][0]\n",
" = (-1)**0 * 2**(0) * (1.5)\n",
" = 1.5\n"
]
}
],
"source": [
"a = myfloat8(f=1.5)\n",
"print(a)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "90a3ec42-ed68-4db3-a73b-fe2c3129932b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"00000000\n",
" = (-1)**[0] * 2**[0][0][0] * [0].[0][0][0]\n",
" = 0.0\n"
]
}
],
"source": [
"a = myfloat8(f=0)\n",
"print(a)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "0236b8c9-1290-441f-96b2-8b80c4039232",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"00111110\n",
" = (-1)**[0] * 2**[0][1][1] * [1].[1][1][1][0]\n",
" = (-1)**0 * 2**(0) * (1.875)\n",
" = 1.875\n"
]
}
],
"source": [
"a = myfloat8(f=1.875)\n",
"print(a)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "5ca7f936-22e0-4826-9202-24841e11d5b9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"01001100\n",
" = (-1)**[0] * 2**[1][0][0] * [1].[1][1][0][0]\n",
" = (-1)**0 * 2**(1) * (1.75)\n",
" = 3.5\n"
]
}
],
"source": [
"a = myfloat8(f=3.5)\n",
"print(a)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "fd82a5db-e620-4cd1-bff7-75b4d2560593",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"01000000\n",
" = (-1)**[0] * 2**[1][0][0] * [1].[0][0][0][0]\n",
" = (-1)**0 * 2**(1) * (1.0)\n",
" = 2.0\n"
]
}
],
"source": [
"a = myfloat8(f=2)\n",
"print(a)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "5b79d45b-480d-486a-b52f-769ceba11930",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"00011000\n",
" = (-1)**[0] * 2**[0][0][1] * [1].[1][0][0][0]\n",
" = (-1)**0 * 2**(-2) * (1.5)\n",
" = 0.375\n"
]
}
],
"source": [
"a = myfloat8(f=0.375)\n",
"print(a)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "7516b7e4-33c7-4c78-ab14-4b5a6edeead3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"00011000\n",
" = (-1)**[0] * 2**[0][0][1] * [1].[1][0][0][0]\n",
" = (-1)**0 * 2**(-2) * (1.5)\n",
" = 0.375\n",
"10110100\n",
" = (-1)**[1] * 2**[0][1][1] * [1].[0][1][0][0]\n",
" = (-1)**1 * 2**(0) * (1.25)\n",
" = -1.25\n"
]
}
],
"source": [
"a = myfloat8(f=0.375)\n",
"b = myfloat8(f=-1.25)\n",
"print(a)\n",
"print(b)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "abefdecc-ebd8-4a8a-8811-a5d857f0ead6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Currently ``__add__'' is not completely implemented.\n"
]
},
{
"data": {
"text/plain": [
"00011000\n",
" = (-1)**[0] * 2**[0][0][1] * [1].[1][0][0][0]\n",
" = (-1)**0 * 2**(-2) * (1.5)\n",
" = 0.375"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a+b"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "25b5ac63-d9ef-438d-b1b4-36c75e026808",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Currently ``__mul__'' is not implemented.\n"
]
},
{
"data": {
"text/plain": [
"00011000\n",
" = (-1)**[0] * 2**[0][0][1] * [1].[1][0][0][0]\n",
" = (-1)**0 * 2**(-2) * (1.5)\n",
" = 0.375"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a*b"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3eb45f73-1cdb-4642-aa76-19435c42e45a",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "py-conda",
"language": "python",
"name": "py-conda"
},
"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.10.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment