Skip to content

Instantly share code, notes, and snippets.

@matiasmicheletto
Created June 25, 2022 15:06
Show Gist options
  • Save matiasmicheletto/aa659267e71805656991ca52143803ae to your computer and use it in GitHub Desktop.
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
<!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