{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "In this lecture 7 of MCS 320, we look at binary and hexadecimal formats of numbers, introduce the nearby rational approximations in the first section. In the second section we illustrate how functions can be used to store data." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1. Number Types" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The number types ``ZZ``, ``QQ``, ``RR``, and ``CC`` abbreviate respectively the integer, rational, real, and complex numbers." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use ``ZZ`` to compute the digits of the binary expansion of a number." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1]" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ZZ(2022).digits(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Given the list of the bits in a number, we can convert back to its decimal representation." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2022" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d = ZZ(2022).digits(2)\n", "ZZ(d, base=2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the real field ``RR``, we can ask the precision." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "53" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "RR.precision()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a real number, we can ask the hexadecimal representation." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-0.414516219983697\n" ] } ], "source": [ "r = RR.random_element()\n", "print(r)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'-0x6.a1dbc287dd46p-4'" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r.hex()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us consider the strange case of ``0.1``..." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'0x1.999999999999ap-4'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nbr = RR(0.1)\n", "nbr.hex()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'0x1.999999999999999999999999ap-4'" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "R100 = RealField(prec=100)\n", "nbr = R100(0.1)\n", "nbr.hex()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When going from 53 bits to 100 bits of precision, we see that the hexadecimal expansion of ``0.1`` does not stop. This implies that ``0.1`` has no exact *binary* representation, unlike in decimal notation, where the expansion ``0.1`` matches $1/10$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For any real number, we can ask for its nearest rational number, with an upper bound on the size of the denominator." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x = -0.657062363581058\n" ] }, { "data": { "text/plain": [ "-23/35" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = RR.random_element()\n", "print('x = ', x)\n", "x.nearby_rational(max_denominator=100)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[-2/3,\n", " -23/35,\n", " -228/347,\n", " -5131/7809,\n", " -5131/7809,\n", " -471117/717005,\n", " -1175227/1788608,\n", " -64166368/97656435,\n", " -255490245/388837132,\n", " -6515588861/9916241170]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[x.nearby_rational(max_denominator=10^k) for k in range(1, 11)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is the third type of rational approximations we encounter. The previous two types were\n", "\n", "1. Rational approximations with prescribed precision.\n", "\n", "2. The convergents of the continued fraction representation of the number.\n", "\n", "In this third type we control the size of the rational number." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 2. Functions to Store Data" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "reset()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The list is a composite data structure. The assignment ``L = [3, 2, 0]`` makes not only the list ``L`` but also the names ``L[0]``, ``L[1]``, and ``L[2]``." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use functions to store data as illustrated in the example below." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "def fun(item, data=[]):\n", " \"\"\"\n", " Appends the item to data and prints data.\n", " \"\"\"\n", " data.append(item)\n", " print(data)\n", " return id(data)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[3]\n" ] }, { "data": { "text/plain": [ "123135382038160" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fun(3)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[3, 2]\n" ] }, { "data": { "text/plain": [ "123135382038160" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fun(2)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[3, 2, 0]\n" ] }, { "data": { "text/plain": [ "123135382038160" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fun(0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that the value of ``id(data)`` remains the same." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[3, 2, 0, 4]\n" ] } ], "source": [ "idofdata = fun(4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With ``ctypes`` we can retrieve the value of an object, given its address." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[3, 2, 0, 4]\n" ] } ], "source": [ "import ctypes\n", "dataList = ctypes.cast(idofdata, ctypes.py_object).value\n", "print(dataList)" ] } ], "metadata": { "kernelspec": { "display_name": "SageMath 10.3", "language": "sage", "name": "sagemath" }, "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" } }, "nbformat": 4, "nbformat_minor": 4 }