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.
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.
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.
| n | Expresión | aₙ |
|---|---|---|
| 1 | −1/1 | −1 |
| 2 | 1/2 | 0.5 |
| 3 | −1/3 | −0.3333… |
| 4 | 1/4 | 0.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.
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:
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.
| Decisión | Efecto | Precaución |
|---|---|---|
| Cantidad de términos | Muestra comportamiento inicial o más lejano. | Muchos puntos pueden superponerse. |
| Rango vertical automático | Aprovecha el espacio disponible. | Gráficos distintos pueden parecer comparables sin serlo. |
| Escala logarítmica | Hace visibles órdenes de magnitud. | No admite valores negativos en su forma usual. |
| Unión de puntos | Destaca 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
requestAnimationFramesi 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.
Visualizador de sucesiones
aₙ = 1/n
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
- Aumentá los términos de
1/n. ¿Por qué los primeros parecen comprimirse? - Compará la sucesión cuadrática con el decaimiento geométrico.
- Usá la alternante: ¿qué aporta conservar el eje horizontal?
- 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.