Sucesiones · Tema 03

Generación y visualización con JavaScript

Cómo convertir una regla matemática en datos verificables y representar términos discretos mediante arreglos, tablas, generadores y gráficos.

01 · Punto de partida

De una regla infinita a datos finitos

Una sucesión matemática puede tener infinitos términos, pero un programa solo ejecuta una cantidad finita de operaciones y almacena una cantidad finita de datos. Para explorarla debemos elegir un fragmento: los primeros términos, un intervalo de índices o ciertas posiciones concretas.

Supongamos aₙ = 1/n, con n ≥ 1. La regla describe toda la sucesión, mientras que un arreglo como [1, 0.5, 0.333…, 0.25] contiene solamente cuatro muestras. La diferencia es fundamental:

  • La regla matemática permite consultar cualquier índice admitido.
  • El arreglo materializa un conjunto finito de términos.
  • La tabla asocia explícitamente cada índice con su valor.
  • El gráfico representa esos pares como puntos discretos.
  • La visualización depende de escalas, dimensiones y decisiones de diseño.

02 · Diseño del programa

Separar modelo, generación y presentación

Un programa claro divide el trabajo en tres capas. Esta separación permite probar la matemática sin depender del gráfico y cambiar la representación sin reescribir la sucesión.

an

Modelo

Una función recibe el índice y devuelve el término correspondiente.

[ ]

Generación

Selecciona índices y construye los pares que se desean observar.

▥

Presentación

Convierte los datos en texto, tabla, archivo o gráfico.

const reciproca = n => 1 / n;

function generarPares(regla, desde, cantidad) {
  return Array.from({ length: cantidad }, (_, posicion) => {
    const n = desde + posicion;
    return { n, valor: regla(n) };
  });
}

const datos = generarPares(reciproca, 1, 5);
console.log(datos);

reciproca contiene el modelo; generarPares decide qué términos materializar; console.log es una presentación. Cada parte puede reemplazarse de forma independiente.

03 · Generación finita

Construir arreglos de términos

Array.from es conveniente cuando conocemos de antemano la cantidad de términos. Su segundo argumento recibe la posición del arreglo, que comienza en cero.

índice matemático = índice inicial + posición del arreglo
function generarSucesion(regla, opciones) {
  const { inicio = 1, cantidad = 10 } = opciones;
  if (!Number.isInteger(inicio) || !Number.isInteger(cantidad) || cantidad < 0) {
    throw new RangeError("Inicio y cantidad deben ser enteros válidos");
  }

  return Array.from({ length: cantidad }, (_, posicion) => {
    const indice = inicio + posicion;
    return { indice, termino: regla(indice) };
  });
}

const cuadrados = generarSucesion(n => n ** 2, { inicio: 1, cantidad: 6 });
console.log(cuadrados);

Generar un intervalo inclusivo

A veces resulta más natural indicar los índices inicial y final. Si ambos extremos se incluyen, la cantidad es fin − inicio + 1.

function generarIntervalo(regla, inicio, fin) {
  if (!Number.isInteger(inicio) || !Number.isInteger(fin) || fin < inicio) {
    throw new RangeError("Intervalo de índices inválido");
  }
  const cantidad = fin - inicio + 1;
  return Array.from({ length: cantidad }, (_, i) => ({
    n: inicio + i,
    valor: regla(inicio + i)
  }));
}

console.log(generarIntervalo(n => 2 * n - 1, 4, 8));

04 · Sucesiones recursivas

Generar términos conservando el estado

Una fórmula explícita permite evaluar índices de forma independiente. Una recurrencia requiere conservar uno o más términos anteriores. Para Fibonacci basta guardar los dos últimos si solo queremos recorrer la sucesión:

function generarFibonacci(cantidad) {
  const resultado = [];
  let anterior = 0;
  let actual = 1;

  for (let n = 0; n < cantidad; n += 1) {
    resultado.push({ n, valor: anterior });
    [anterior, actual] = [actual, anterior + actual];
  }
  return resultado;
}

console.log(generarFibonacci(10));

El algoritmo necesita memoria constante para producir el siguiente término, aunque el arreglo final ocupa memoria proporcional a la cantidad solicitada. Si procesamos cada término inmediatamente, ni siquiera es necesario conservarlos todos.

05 · Evaluación perezosa

Generadores: producir valores bajo demanda

Una función generadora pausa su ejecución en cada yield. Esto permite representar un proceso potencialmente ilimitado sin construir un arreglo infinito.

function* fibonacci() {
  let anterior = 0;
  let actual = 1;
  let n = 0;

  while (true) {
    yield { n, valor: anterior };
    [anterior, actual] = [actual, anterior + actual];
    n += 1;
  }
}

const flujo = fibonacci();
const primeros = Array.from({ length: 8 }, () => flujo.next().value);
console.log(primeros);

Arreglo

Materialización inmediata

Es fácil de recorrer varias veces, filtrar y graficar, pero almacena todos los elementos generados.

Generador

Producción bajo demanda

Consume poca memoria y sirve para flujos, pero sus valores se consumen en orden.

La existencia de while (true) no bloquea el programa porque cada yield devuelve el control. El consumidor debe limitar cuántos valores solicita.

06 · Representación tabular

Una tabla conserva la correspondencia

Mostrar únicamente los valores puede ocultar el índice inicial. Una tabla de objetos mantiene juntos n y aₙ, permite inspeccionar resultados y facilita exportarlos.

Primeros términos de aₙ = (−1)ⁿ/n.
nExpresiónaₙ
1−1/1−1
21/20.5
3−1/3−0.3333…
41/40.25
function formatearTabla(datos, decimales = 4) {
  return datos.map(({ n, valor }) =>
    `n=${n}: ${valor.toFixed(decimales)}`
  ).join("\n");
}

const datos = Array.from({ length: 6 }, (_, i) => {
  const n = i + 1;
  return { n, valor: (-1) ** n / n };
});

console.log(formatearTabla(datos));

Redondear para mostrar no debe alterar los valores internos. Conservamos el número original y aplicamos toFixed únicamente al producir texto.

07 · Representación gráfica

Del par (n, aₙ) a un píxel

En el plano matemático, el eje horizontal representa el índice y el vertical el término. En un canvas, el origen está arriba a la izquierda y la coordenada vertical aumenta hacia abajo. Necesitamos transformar escalas.

x = margen + (n − nmín) / (nmáx − nmín) · ancho útil
y = base − (an − ymín) / (ymáx − ymín) · alto útil
function crearEscala(minDato, maxDato, minPixel, maxPixel) {
  if (maxDato === minDato) return () => (minPixel + maxPixel) / 2;
  return valor => minPixel +
    (valor - minDato) / (maxDato - minDato) * (maxPixel - minPixel);
}

const escalaX = crearEscala(1, 10, 50, 850);
console.log("n=1 →", escalaX(1), "px");
console.log("n=10 →", escalaX(10), "px");

Cada término debe mostrarse como punto. Las líneas verticales hasta el eje ayudan a identificar valores. Unir puntos puede servir para guiar la vista, pero debe aclararse que los segmentos no agregan términos.

08 · Escala y encuadre

El gráfico también interpreta

Antes de dibujar calculamos el mínimo y máximo de los valores visibles. Un margen adicional evita que los puntos extremos queden pegados al borde:

margen vertical = 0,1 · (máximo − mínimo)

Si todos los términos visibles son iguales, el rango es cero y la fórmula de escala dividiría por cero. En ese caso podemos centrar los puntos y usar un rango artificial alrededor del valor.

Decisiones que modifican la lectura.
DecisiónEfectoPrecaución
Cantidad de términosMuestra comportamiento inicial o más lejano.Muchos puntos pueden superponerse.
Rango vertical automáticoAprovecha el espacio disponible.Gráficos distintos pueden parecer comparables sin serlo.
Escala logarítmicaHace visibles órdenes de magnitud.No admite valores negativos en su forma usual.
Unión de puntosDestaca tendencias.Puede sugerir continuidad inexistente.

09 · Datos confiables

Validar índices y resultados numéricos

Una regla puede producir NaN o Infinity por un índice inválido, una operación fuera de dominio o desbordamiento numérico. Es preferible detectar el problema antes de enviarlo al gráfico.

function generarDatosSeguros(regla, inicio, cantidad) {
  const datos = [];
  for (let posicion = 0; posicion < cantidad; posicion += 1) {
    const n = inicio + posicion;
    const valor = regla(n);
    if (!Number.isFinite(valor)) {
      throw new RangeError(`Término no finito en n=${n}: ${valor}`);
    }
    datos.push({ n, valor });
  }
  return datos;
}

console.log(generarDatosSeguros(n => 1 / n, 1, 5));

Number.isFinite rechaza infinitos y resultados que no son números. Esto no elimina errores de redondeo, pero evita que coordenadas inválidas se propaguen al dibujo.

10 · Rendimiento y precisión

Generar lo necesario, representar lo legible

Crear un millón de términos para dibujarlos en un lienzo de 900 píxeles rara vez aporta un millón de detalles visibles. Conviene distinguir la precisión del cálculo de la resolución de la pantalla.

  • Limitá la cantidad según el objetivo de exploración.
  • Calculá una vez y reutilizá los datos mientras no cambie la regla.
  • Redibujá mediante requestAnimationFrame si los controles generan muchas actualizaciones.
  • Para conjuntos enormes, agregá o seleccioná muestras representativas sin falsificar extremos.
  • No redondees durante la recurrencia salvo que el modelo lo requiera.

Seleccionar muestras conservando extremos

function seleccionarMuestras(datos, maximo) {
  if (datos.length <= maximo) return datos;
  const paso = (datos.length - 1) / (maximo - 1);
  return Array.from({ length: maximo }, (_, i) =>
    datos[Math.round(i * paso)]
  );
}

const datos = Array.from({ length: 1000 }, (_, n) => ({ n, valor: Math.sqrt(n) }));
console.log(seleccionarMuestras(datos, 8));

11 · Exploración interactiva

Laboratorio: representar términos discretos

Elegí una sucesión, cuántos términos mostrar y el estilo visual. El modo «puntos» conserva la representación mínima; «tallos» facilita leer cada valor; «guía» conecta puntos solo como ayuda visual.

EXPERIMENTO 03

Visualizador de sucesiones

aₙ = 1/n

Los valores principales aparecen debajo.
Índice inicialn = 1
Primer términoa₁ = 1
Último visiblea₁₅ = 0,0667
Rango vertical0,0667 a 1

Se muestran 15 términos mediante puntos y tallos.

Los términos son puntos discretos. En el modo guía, los segmentos solo orientan la vista y no representan índices intermedios.

Preguntas para explorar

  1. Aumentá los términos de 1/n. ¿Por qué los primeros parecen comprimirse?
  2. Compará la sucesión cuadrática con el decaimiento geométrico.
  3. Usá la alternante: ¿qué aporta conservar el eje horizontal?
  4. Cambiá entre puntos, tallos y guía. ¿Qué interpretación podría inducir cada modo?

12 · Reutilización

Exportar los datos sin perder el índice

Un formato CSV permite llevar los términos a una hoja de cálculo o herramienta de análisis. Incluimos encabezados y conservamos precisión numérica razonable.

function convertirACsv(datos) {
  const filas = datos.map(({ n, valor }) => `${n},${valor}`);
  return ["n,valor", ...filas].join("\n");
}

const datos = Array.from({ length: 5 }, (_, i) => {
  const n = i + 1;
  return { n, valor: 1 / n };
});

console.log(convertirACsv(datos));

Para descargarlo en una aplicación web podríamos crear un Blob y un enlace temporal. Aquí mostramos el texto para mantener el ejemplo seguro y ejecutable dentro de la lección.

Accesibilidad del gráfico

El lienzo no debe ser la única fuente de información. Un texto alternativo, un resumen actualizado y una tabla permiten comprender los datos sin depender del color o de la percepción visual del gráfico.

13 · Comprensión

Confusiones frecuentes

«El arreglo es la sucesión completa»

El arreglo contiene una muestra finita. La sucesión está determinada por la regla y su dominio.

«La posición cero siempre representa a₀»

Depende del índice inicial. Si comienza en uno, la posición cero del arreglo representa a₁.

«Unir puntos vuelve continua a la sucesión»

La línea es una decisión gráfica. Los únicos términos siguen estando en índices naturales.

«Más términos siempre producen un gráfico mejor»

La resolución es finita; demasiados puntos pueden ocultar patrones y consumir recursos sin aportar información.

«toFixed aumenta la precisión»

Solo formatea una representación textual. No recupera información perdida ni mejora el cálculo.

«El gráfico demuestra el comportamiento infinito»

Solo muestra términos finitos. Sirve para explorar y formular conjeturas, no para reemplazar una demostración.

14 · Práctica y síntesis

Ejercicios de comprensión

Ejercicio 1: generar un intervalo

Generá los términos de aₙ = 3n−2 desde n=5 hasta n=9, conservando índices y valores.

Ver solución
const datos = Array.from({ length: 5 }, (_, posicion) => {
  const n = 5 + posicion;
  return { n, valor: 3 * n - 2 };
});
console.log(datos);

Ejercicio 2: diagnosticar el desfase

¿Qué representa el primer elemento de Array.from({length: 5}, (_, n) => 1/(n+1))? ¿Por qué la posición y el índice matemático no coinciden?

Ver solución razonada

La posición cero produce 1/(0+1)=1, que representa a₁. El arreglo numera posiciones desde cero; la sucesión fue definida desde uno.

Ejercicio 3: generador limitado

Creá un generador de potencias de dos y consumí solo sus primeros seis valores.

Ver solución
function* potenciasDeDos() {
  let valor = 1;
  while (true) {
    yield valor;
    valor *= 2;
  }
}

const generador = potenciasDeDos();
const primeros = Array.from({ length: 6 }, () => generador.next().value);
console.log(primeros); // [1, 2, 4, 8, 16, 32]

Ejercicio 4: diseñar una visualización

Para aₙ=(−1)ⁿ·n, explicá qué rango vertical usarías y por qué una escala que comience en cero pero solo muestre positivos sería incorrecta.

Ver una posible respuesta

El rango debe incluir el mínimo negativo, el máximo positivo y el cero. Omitir la zona negativa escondería la alternancia. Conviene dibujar el eje horizontal y puntos o tallos para conservar el carácter discreto.

Ideas para recordar

  • Un programa materializa una porción finita de una sucesión infinita.
  • Separar modelo, generación y presentación facilita pruebas y reutilización.
  • Arreglos sirven para colecciones finitas; generadores, para producción bajo demanda.
  • Los pares (n,aₙ) conservan la correspondencia entre índice y término.
  • La transformación a píxeles debe contemplar márgenes, rangos nulos y eje vertical invertido.
  • Los gráficos de sucesiones deben preservar su naturaleza discreta.
  • Validación, muestreo y accesibilidad forman parte de una visualización confiable.

En el próximo tema estudiaremos sucesiones aritméticas y geométricas, sus parámetros, fórmulas, comportamiento y aplicaciones.