Created
June 25, 2022 15:06
-
-
Save matiasmicheletto/aa659267e71805656991ca52143803ae to your computer and use it in GitHub Desktop.
JS para computación científica: Estimación de PI con método Monte Carlo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<!-- Título de la página, visible en la barra del navegador --> | |
<title>Método Monte Carlo en el navegador</title> | |
</head> | |
<body> | |
<div style="margin:15px;"> | |
<!-- Aquí definimos los elementos del documento que funcionará como | |
interface gráfica. Utilizaremos elementos nativos de HTML. Notar que | |
aquellos elementos que vamos a controlar, llevan un atributo único | |
"id" para identificarlos. --> | |
<h3>Estimador de PI mediante Monte Carlo</h3> | |
<!-- Usamos un input para que el usuario indique el número de | |
iteraciones y que tendrá un valor por defecto de 100.000 --> | |
<p>Iteraciones: <input id="input" type="number" value="100000"></p> | |
<!-- Con el siguiente botón, vamos a permitir que el usuario ejecute | |
la simulación --> | |
<button id="button">¡Ejecutar!</button> | |
<!-- El "canvas" es el espacio en el que graficaremos la simulación --> | |
<div style="margin: 20px 0px;"> | |
<canvas | |
id="canvas" | |
height="500" width="500" | |
style="border: 1px solid black;"> | |
</canvas> | |
</div> | |
<!-- Finalmente, agregamos un texto para mostrar el resultado de la | |
estimación y el error porcentual al comparar la estimación con el | |
valor de la constante PI (representado con 64 bit) --> | |
<p><b>Resultado: </b><span id="result">???</span></p> | |
</div> | |
<!-- Dentro del tag "script" podemos poner código javascript para ejecutar | |
luego de que se complete la carga del documento --> | |
<script type="text/javascript"> | |
// Primero vamos a crear las referencias a los elementos del documento. | |
// El id especificado como argumento debe coincidir con el indicado en | |
// el atributo "id" de cada elemento del documento. | |
// El elemento "input" desde el cual leemos el parámetro de entrada, | |
// que en este caso será la cantidad de iteraciones a realizar. Las | |
// variables que están definidas con "const" no se podrán modificar, | |
// en cambio usamos "let" para las que si. | |
const inputEl = document.getElementById("input"); | |
// Para el caso del elemento "button", definiremos un "callback" más | |
// abajo que contiene las instrucciones a ejecutar cada vez que se lo | |
// presione. | |
const btn = document.getElementById("button"); | |
// En el elemento "span", mostraremos el resultado numérico de la | |
// estimación. | |
const resEl = document.getElementById("result"); | |
// El "canvas" y su "context" son los objetos que nos permitirán | |
// realizar la visualización del método. | |
const canvas = document.getElementById("canvas"); | |
const ctx = canvas.getContext("2d"); | |
// Necesitaremos las dimensiones del "canvas" para escalar el espacio | |
// de coordenadas | |
const W = canvas.width; | |
const H = canvas.height; | |
// Vamos a valernos de unas funciones para aquellas instrucciones que | |
// debemos repetir múltiples veces | |
// Graficar un punto de color en una posición (x,y) del canvas | |
const plot = (x, y, color) => { | |
// El color del punto debe especificarse en el argumento | |
ctx.fillStyle = color; | |
// Nuestro punto será un pequeño cuadrado de 1x1 pixeles, y para | |
// escalar el espacio de coordenadas al tamaño del canvas, | |
// multiplicamos "x" e "y" por "W" y "H" respectivamente. | |
ctx.fillRect(x * W, y * H, 1, 1); | |
}; | |
// Borrar gráficos | |
const clearPlot = () => { | |
ctx.clearRect(0, 0, W, H); | |
}; | |
// Esta función implementa el método para estimar Pi y graficar | |
// el punto aleatoriamente muestreado de cada iteración | |
const estimatePi = N => { | |
let cnt = 0; // Iniciar contador | |
for(let i = 0; i < N; i++){ | |
// Generar un punto aleatorio con distribución uniforme | |
// en el interior de un cuadrado de lado 1 | |
const x = Math.random(); | |
const y = Math.random(); | |
// Determinar si el punto cae dentro o fuera del círculo | |
// unitario | |
const cond = x*x + y*y <= 1; | |
// Graficar punto y color dependiendo de la condición | |
plot(x, y, cond ? "red" : "blue"); | |
// Contar cuántos puntos caen dentro del círculo | |
if(cond) cnt++; | |
} | |
// Presentar resultado | |
return 4 * cnt / N; | |
}; | |
// Programamos la función para el evento "on click" del botón de | |
// ejecutar | |
btn.onclick = () => { | |
btn.disabled = true; | |
clearPlot(); // Borrar gráfica | |
// Leer el valor del input y convertirlo a número entero | |
const iters = parseInt(inputEl.value); | |
// Correr el método. Esto puede demorar algo para valores grandes | |
// y el navegador puede mostrar el mensaje de que el sitio no | |
// responde | |
const result = estimatePi(iters); | |
const er = (Math.PI - result)/Math.PI*100; | |
// Actualizamos el valor del resultado con 10 cifras y el error | |
// porcentual para que se muestre en el documento | |
resEl.innerHTML = `${result.toFixed(10)} (${er.toFixed(2)}%)`; | |
btn.disabled = false; | |
}; | |
// Vamos a llamar esta función para que se ejecute al cargar la página. | |
btn.onclick(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment