{
"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
}