.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/numerical_analysis/floating_point/plot_02_ieee754_machine_epsilon.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code or to run this example in your browser via JupyterLite. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_numerical_analysis_floating_point_plot_02_ieee754_machine_epsilon.py: IEEE 754: bit layouts, machine epsilon, and the spacing of floats ================================================================= The IEEE 754 standard of 1985 fixed how a binary floating-point number is stored: a sign bit, a biased exponent, and a fraction, with value :math:`(-1)^s (1.f)_2 \cdot 2^{e}`. It also fixed the rounding rule (round to nearest, ties to even) and the special values (signed zeros, subnormals, infinities, NaN). Machine epsilon, the gap between 1 and the next float, is :math:`2^{-52}` in double precision. Floats are equally spaced within each binade :math:`[2^e, 2^{e+1})`, and the spacing doubles from one binade to the next, so their *relative* spacing stays roughly constant. .. GENERATED FROM PYTHON SOURCE LINES 17-22 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from mathematicskit.numerical_analysis import float_bits, machine_epsilon, toy_float_system, ulp .. GENERATED FROM PYTHON SOURCE LINES 23-25 Decoding the bit fields ----------------------- .. GENERATED FROM PYTHON SOURCE LINES 25-43 .. code-block:: Python for x in (1.0, 0.1, -2.5, 5e-324): b = float_bits(x) print(f"{x!r:>8}: sign {b.sign} | exponent {b.exponent_bits} (2^{b.exponent}) | fraction {b.fraction_bits[:16]}... | {b.category}") for dtype in (np.float16, np.float32, np.float64): print(f"{np.dtype(dtype).name:>8}: machine epsilon {machine_epsilon(dtype):.3e} = 2^{int(np.log2(machine_epsilon(dtype)))}") fig, axes = plt.subplots(3, 1, figsize=(10, 9), gridspec_kw={"height_ratios": [1, 1.2, 2]}) bits = float_bits(0.1) word = str(bits.sign) + bits.exponent_bits + bits.fraction_bits colors = ["tab:red"] + ["tab:green"] * 11 + ["tab:blue"] * 52 axes[0].bar(np.arange(64), 1, color=colors, edgecolor="white", width=1.0) for i, ch in enumerate(word): axes[0].text(i, 0.5, ch, ha="center", va="center", color="white", fontsize=7) axes[0].set_axis_off() axes[0].set_title("0.1 in binary64: sign (red), 11-bit exponent (green), 52-bit fraction (blue)") .. image-sg:: /api/gallery/numerical_analysis/floating_point/images/sphx_glr_plot_02_ieee754_machine_epsilon_001.png :alt: 0.1 in binary64: sign (red), 11-bit exponent (green), 52-bit fraction (blue) :srcset: /api/gallery/numerical_analysis/floating_point/images/sphx_glr_plot_02_ieee754_machine_epsilon_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none 1.0: sign 0 | exponent 01111111111 (2^0) | fraction 0000000000000000... | normal 0.1: sign 0 | exponent 01111111011 (2^-4) | fraction 1001100110011001... | normal -2.5: sign 1 | exponent 10000000000 (2^1) | fraction 0100000000000000... | normal 5e-324: sign 0 | exponent 00000000000 (2^-1022) | fraction 0000000000000000... | subnormal float16: machine epsilon 9.766e-04 = 2^-10 float32: machine epsilon 1.192e-07 = 2^-23 float64: machine epsilon 2.220e-16 = 2^-52 Text(0.5, 1.0, '0.1 in binary64: sign (red), 11-bit exponent (green), 52-bit fraction (blue)') .. GENERATED FROM PYTHON SOURCE LINES 44-49 A toy floating-point system --------------------------- With a 3-bit significand every binade holds four numbers. Subnormals (orange) fill the gap between 0 and the smallest normal number evenly. .. GENERATED FROM PYTHON SOURCE LINES 49-62 .. code-block:: Python normal = toy_float_system(precision=3, emin=-1, emax=3) with_sub = toy_float_system(precision=3, emin=-1, emax=3, subnormals=True) subnormal = np.setdiff1d(with_sub, normal) axes[1].plot(normal, np.zeros_like(normal), "|", ms=25, color="tab:blue", label="normal") axes[1].plot(subnormal, np.zeros_like(subnormal), "|", ms=25, color="tab:orange", label="subnormal") for e in range(-1, 4): axes[1].axvline(2.0 ** (e - 1), color="gray", lw=0.5, ls=":") axes[1].set_yticks([]) axes[1].set_xlabel("x") axes[1].set_title("t = 3, e in [-1, 3]: spacing doubles at every power of two") axes[1].legend(loc="upper left") .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 63-65 ulp(x) is a staircase that follows eps times abs(x) --------------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 65-76 .. code-block:: Python x = np.logspace(-3, 3, 2000) for dtype, color in ((np.float32, "tab:purple"), (np.float64, "tab:blue")): axes[2].loglog(x, ulp(x, dtype), color=color, label=f"ulp(x), {np.dtype(dtype).name}") axes[2].loglog(x, machine_epsilon(dtype) * x, "--", color=color, lw=0.8, label=rf"$\varepsilon\,|x|$, {np.dtype(dtype).name}") axes[2].set_xlabel("x") axes[2].set_ylabel("gap to the next float") axes[2].legend(fontsize=8) fig.tight_layout() plt.show() .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.889 seconds) .. _sphx_glr_download_api_gallery_numerical_analysis_floating_point_plot_02_ieee754_machine_epsilon.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../../../../lite/lab/index.html?path=api/gallery/numerical_analysis/floating_point/plot_02_ieee754_machine_epsilon.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_02_ieee754_machine_epsilon.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_02_ieee754_machine_epsilon.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_02_ieee754_machine_epsilon.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_