.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/monte_carlo/basics/plot_02_box_muller.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_monte_carlo_basics_plot_02_box_muller.py: Box-Muller normal variates ========================== Every Black-Scholes simulation needs normal random numbers, and a computer produces uniforms. George Box and Mervin Muller (1958) gave an exact transform: if :math:`u_1, u_2` are independent uniforms, .. math:: z_1 = \sqrt{-2\ln u_1}\cos(2\pi u_2), \qquad z_2 = \sqrt{-2\ln u_1}\sin(2\pi u_2) are independent standard normals. The squared radius of a standard bivariate normal is exponential with mean 2 and its angle is uniform, so inverting both gives the pair. .. GENERATED FROM PYTHON SOURCE LINES 17-27 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from scipy.stats import kstest, norm from financialkit.monte_carlo import box_muller, box_muller_normals rng = np.random.default_rng(0) u1, u2 = rng.random((2, 3000)) z1, z2 = box_muller(1.0 - u1, u2) .. GENERATED FROM PYTHON SOURCE LINES 28-32 Uniform square to normal plane ------------------------------ Colouring each uniform pair by its angle :math:`2\pi u_2` shows the map: :math:`u_2` sets the direction and :math:`u_1` the radius. .. GENERATED FROM PYTHON SOURCE LINES 32-40 .. code-block:: Python fig, axes = plt.subplots(1, 3, figsize=(14, 4)) axes[0].scatter(u1, u2, c=u2, s=3, cmap="twilight") axes[0].set_title("uniforms $(u_1, u_2)$") axes[1].scatter(z1, z2, c=u2, s=3, cmap="twilight") axes[1].set_aspect("equal") axes[1].set_title("Box-Muller $(z_1, z_2)$") .. image-sg:: /api/gallery/monte_carlo/basics/images/sphx_glr_plot_02_box_muller_001.png :alt: uniforms $(u_1, u_2)$, Box-Muller $(z_1, z_2)$ :srcset: /api/gallery/monte_carlo/basics/images/sphx_glr_plot_02_box_muller_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Text(0.5, 1.0, 'Box-Muller $(z_1, z_2)$') .. GENERATED FROM PYTHON SOURCE LINES 41-43 The output is normal -------------------- .. GENERATED FROM PYTHON SOURCE LINES 43-53 .. code-block:: Python z = box_muller_normals(100_000, rng=1) x = np.linspace(-4, 4, 200) axes[2].hist(z, bins=80, density=True, alpha=0.6, label="Box-Muller") axes[2].plot(x, norm.pdf(x), "k", label="N(0, 1)") axes[2].legend() axes[2].set_title(f"KS p-value {kstest(z, 'norm').pvalue:.2f}") print(f"mean {z.mean():+.4f}, variance {z.var():.4f}, corr(z1, z2) {np.corrcoef(z1, z2)[0, 1]:+.4f}") fig.tight_layout() plt.show() .. rst-class:: sphx-glr-script-out .. code-block:: none mean +0.0029, variance 0.9990, corr(z1, z2) +0.0012 .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.111 seconds) .. _sphx_glr_download_api_gallery_monte_carlo_basics_plot_02_box_muller.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/monte_carlo/basics/plot_02_box_muller.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_02_box_muller.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_02_box_muller.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_02_box_muller.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_