{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "In lecture 3 we use SageMath as a calculator and explore the help system." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1. Getting Started" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What is the accuracy of 22/7 as an approximation for $\\pi$?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Well, we setup the formula for the relative error:\n", "\n", "$$\n", " \\left| \\frac{22/7 - \\pi}{\\pi} \\right|.\n", "$$ " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\frac{{\\left| 7 \\, \\pi - 22 \\right|}}{7 \\, \\pi}$$" ], "text/plain": [ "1/7*abs(7*pi - 22)/pi" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "error = abs((22/7 - pi)/pi)\n", "show(error)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we evaluate this error numerically, in a number system of sufficiently high precision. For this problem, 5 decimal places will surely be sufficient." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.00040244" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "error.n(digits=5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that the error is ``0.0004`` or $4 \\times 10^{-4}$ which is ``4.0e-4`` in scientific notation, as verified below." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'4.0e-04'" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'%.1e' % 0.0004" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 2. Getting Help" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function numerical_approx in module sage.misc.functional:\n", "\n", "numerical_approx(x, prec=None, digits=None, algorithm=None)\n", " Return a numerical approximation of ``self`` with ``prec`` bits\n", " (or decimal ``digits``) of precision.\n", " \n", " No guarantee is made about the accuracy of the result.\n", " \n", " .. NOTE::\n", " \n", " Lower case :func:`n` is an alias for :func:`numerical_approx`\n", " and may be used as a method.\n", " \n", " INPUT:\n", " \n", " - ``prec`` -- precision in bits\n", " \n", " - ``digits`` -- precision in decimal digits (only used if\n", " ``prec`` is not given)\n", " \n", " - ``algorithm`` -- which algorithm to use to compute this\n", " approximation (the accepted algorithms depend on the object)\n", " \n", " If neither ``prec`` nor ``digits`` is given, the default\n", " precision is 53 bits (roughly 16 digits).\n", " \n", " EXAMPLES::\n", " \n", " sage: numerical_approx(pi, 10)\n", " 3.1\n", " sage: numerical_approx(pi, digits=10)\n", " 3.141592654\n", " sage: numerical_approx(pi^2 + e, digits=20)\n", " 12.587886229548403854\n", " sage: n(pi^2 + e)\n", " 12.5878862295484\n", " sage: N(pi^2 + e)\n", " 12.5878862295484\n", " sage: n(pi^2 + e, digits=50)\n", " 12.587886229548403854194778471228813633070946500941\n", " sage: a = CC(-5).n(prec=40)\n", " sage: b = ComplexField(40)(-5)\n", " sage: a == b\n", " True\n", " sage: parent(a) is parent(b)\n", " True\n", " sage: numerical_approx(9)\n", " 9.00000000000000\n", " \n", " You can also usually use method notation::\n", " \n", " sage: (pi^2 + e).n()\n", " 12.5878862295484\n", " sage: (pi^2 + e).numerical_approx()\n", " 12.5878862295484\n", " \n", " Vectors and matrices may also have their entries approximated::\n", " \n", " sage: v = vector(RDF, [1,2,3])\n", " sage: v.n()\n", " (1.00000000000000, 2.00000000000000, 3.00000000000000)\n", " \n", " sage: v = vector(CDF, [1,2,3])\n", " sage: v.n()\n", " (1.00000000000000, 2.00000000000000, 3.00000000000000)\n", " sage: _.parent()\n", " Vector space of dimension 3 over Complex Field with 53 bits of precision\n", " sage: v.n(prec=20)\n", " (1.0000, 2.0000, 3.0000)\n", " \n", " sage: u = vector(QQ, [1/2, 1/3, 1/4])\n", " sage: n(u, prec=15)\n", " (0.5000, 0.3333, 0.2500)\n", " sage: n(u, digits=5)\n", " (0.50000, 0.33333, 0.25000)\n", " \n", " sage: v = vector(QQ, [1/2, 0, 0, 1/3, 0, 0, 0, 1/4], sparse=True)\n", " sage: u = v.numerical_approx(digits=4)\n", " sage: u.is_sparse()\n", " True\n", " sage: u\n", " (0.5000, 0.0000, 0.0000, 0.3333, 0.0000, 0.0000, 0.0000, 0.2500)\n", " \n", " sage: A = matrix(QQ, 2, 3, range(6))\n", " sage: A.n()\n", " [0.000000000000000 1.00000000000000 2.00000000000000]\n", " [ 3.00000000000000 4.00000000000000 5.00000000000000]\n", " \n", " sage: B = matrix(Integers(12), 3, 8, srange(24))\n", " sage: N(B, digits=2)\n", " [0.00 1.0 2.0 3.0 4.0 5.0 6.0 7.0]\n", " [ 8.0 9.0 10. 11. 0.00 1.0 2.0 3.0]\n", " [ 4.0 5.0 6.0 7.0 8.0 9.0 10. 11.]\n", " \n", " Internally, numerical approximations of real numbers are stored in base-2.\n", " Therefore, numbers which look the same in their decimal expansion might be\n", " different::\n", " \n", " sage: x=N(pi, digits=3); x\n", " 3.14\n", " sage: y=N(3.14, digits=3); y\n", " 3.14\n", " sage: x==y\n", " False\n", " sage: x.str(base=2)\n", " '11.001001000100'\n", " sage: y.str(base=2)\n", " '11.001000111101'\n", " \n", " Increasing the precision of a floating point number is not allowed::\n", " \n", " sage: CC(-5).n(prec=100)\n", " Traceback (most recent call last):\n", " ...\n", " TypeError: cannot approximate to a precision of 100 bits, use at most 53 bits\n", " sage: n(1.3r, digits=20)\n", " Traceback (most recent call last):\n", " ...\n", " TypeError: cannot approximate to a precision of 70 bits, use at most 53 bits\n", " sage: RealField(24).pi().n()\n", " Traceback (most recent call last):\n", " ...\n", " TypeError: cannot approximate to a precision of 53 bits, use at most 24 bits\n", " \n", " As an exceptional case, ``digits=1`` usually leads to 2 digits (one\n", " significant) in the decimal output (see :trac:`11647`)::\n", " \n", " sage: N(pi, digits=1)\n", " 3.2\n", " sage: N(pi, digits=2)\n", " 3.1\n", " sage: N(100*pi, digits=1)\n", " 320.\n", " sage: N(100*pi, digits=2)\n", " 310.\n", " \n", " In the following example, ``pi`` and ``3`` are both approximated to two\n", " bits of precision and then subtracted, which kills two bits of precision::\n", " \n", " sage: N(pi, prec=2)\n", " 3.0\n", " sage: N(3, prec=2)\n", " 3.0\n", " sage: N(pi - 3, prec=2)\n", " 0.00\n", " \n", " TESTS::\n", " \n", " sage: numerical_approx(I)\n", " 1.00000000000000*I\n", " sage: x = QQ['x'].gen()\n", " sage: F. = NumberField(x^2+2, embedding=sqrt(CC(2))*CC.0)\n", " sage: numerical_approx(k)\n", " 1.41421356237309*I\n", " \n", " sage: type(numerical_approx(CC(1/2)))\n", " \n", " \n", " The following tests :trac:`10761`, in which ``n()`` would break when\n", " called on complex-valued algebraic numbers. ::\n", " \n", " sage: E = matrix(3, [3,1,6,5,2,9,7,3,13]).eigenvalues(); E\n", " [18.16815365088822?, -0.08407682544410650? - 0.2190261484802906?*I, -0.08407682544410650? + 0.2190261484802906?*I]\n", " sage: E[1].parent()\n", " Algebraic Field\n", " sage: [a.n() for a in E]\n", " [18.1681536508882, -0.0840768254441065 - 0.219026148480291*I, -0.0840768254441065 + 0.219026148480291*I]\n", " \n", " Make sure we've rounded up log(10,2) enough to guarantee\n", " sufficient precision (:trac:`10164`)::\n", " \n", " sage: ks = 4*10**5, 10**6\n", " sage: check_str_length = lambda k: len(str(numerical_approx(1+10**-k,digits=k+1)))-1 >= k+1\n", " sage: check_precision = lambda k: numerical_approx(1+10**-k,digits=k+1)-1 > 0\n", " sage: all(check_str_length(k) and check_precision(k) for k in ks)\n", " True\n", " \n", " Testing we have sufficient precision for the golden ratio (:trac:`12163`), note\n", " that the decimal point adds 1 to the string length::\n", " \n", " sage: len(str(n(golden_ratio, digits=5000)))\n", " 5001\n", " sage: len(str(n(golden_ratio, digits=5000000))) # long time (4s on sage.math, 2012)\n", " 5000001\n", " \n", " Check that :trac:`14778` is fixed::\n", " \n", " sage: n(0, algorithm='foo')\n", " 0.000000000000000\n", "\n" ] } ], "source": [ "help(n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ``n()`` is an alias for the method ``numerical_approx``. Observe the statement\n", "``No guarantee is made about the accuracy of the result.``" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we would not know either ``n()`` nor ``numerical_approx`` and wanted to compute a numerical approximation, then we could search the entire SageMath documentation for the words ``numerical approximation``, as follows:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "search_doc(\"numerical_approximation\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The output is moved to the Jupyter Pager window." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The result is rather extensive. The documentation of SageMath is organized into constructions, tutorials, preps (for undergraduates), and the reference manual." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3. Arbitrary Precision Floating-Point Numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One strength of computer algebra systems is that we are not limited to the machine precision and that we can work with arbitrary precision." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ``RealField`` defines arithmetic with arbitrary precision, defined in bits." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To calculate how many bits are needed to have a desired precision in decimal places, we use the 2-logarithm of 10." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "number of bits for 8 decimal places : 27\n" ] } ], "source": [ "p = ceil(8.0*log(10.0,2))\n", "print(\"number of bits for 8 decimal places :\", p)\n", "R8 = RealField(prec=p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can use ``R8`` to get an 8-digit decimal approximation for $\\pi$." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.141593" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "R8(pi)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us verify with what we have seen before." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.1415927" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pi.n(digits=8)" ] } ], "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.14" } }, "nbformat": 4, "nbformat_minor": 2 }