23. Funciones piso y techo

Las funciones piso y techo convierten números reales en enteros mediante redondeo controlado. Son esenciales para dividir datos en grupos, calcular índices, expresar límites y analizar algoritmos discretos.

23.1 Introducción

Muchos problemas de programación necesitan pasar de una cantidad continua o fraccionaria a una cantidad entera: cuántas páginas se requieren, qué índice corresponde a una posición, cuántos bloques se deben procesar o dónde dividir un arreglo.

La función piso redondea hacia abajo y la función techo redondea hacia arriba. No son sinónimos del redondeo habitual: siempre producen enteros con una relación precisa respecto del valor original.

23.2 Función piso

El piso de un número real x, escrito ⌊x⌋, es el mayor entero que no supera a x.

⌊x⌋ = el entero m tal que m ≤ x < m + 1.

⌊4,7⌋ = 4.
⌊4⌋ = 4.
⌊-2,3⌋ = -3.

El último ejemplo es importante: piso no elimina simplemente los decimales. Para -2,3, el entero más grande que sigue siendo menor o igual que -2,3 es -3.

23.3 Función techo

El techo de un número real x, escrito ⌈x⌉, es el menor entero que es mayor o igual que x.

⌈x⌉ = el entero m tal que m - 1 < x ≤ m.

⌈4,2⌉ = 5.
⌈4⌉ = 4.
⌈-2,3⌉ = -2.

El techo permite contar unidades completas necesarias para cubrir una cantidad. Si hay 23 elementos y cada página muestra 10, se necesitan ⌈23/10⌉ = 3 páginas.

23.4 Comparación entre piso, techo y redondeo

x⌊x⌋⌈x⌉Redondeo al entero más cercano
3,2343
3,8344
-2,3-3-2-2
-2,8-3-2-3

El redondeo al más cercano depende de la distancia a los enteros vecinos. Piso y techo no: sus direcciones son fijas.

23.5 Piso y techo en JavaScript

const valores = [4.7, 4, -2.3, -2.8];

for (const valor of valores) {
  console.log({ valor, piso: Math.floor(valor), techo: Math.ceil(valor) });
}
// { valor: 4.7, piso: 4, techo: 5 }
// { valor: 4, piso: 4, techo: 4 }
// { valor: -2.3, piso: -3, techo: -2 }
// { valor: -2.8, piso: -3, techo: -2 }

JavaScript implementa estas funciones como Math.floor y Math.ceil. Conviene recordar el comportamiento con negativos antes de usar piso como si fuera una simple conversión a entero.

23.6 Propiedades básicas

⌊x⌋ ≤ x < ⌊x⌋ + 1.
⌈x⌉ - 1 < x ≤ ⌈x⌉.

Si x es entero: ⌊x⌋ = ⌈x⌉ = x.

Para todo real x: ⌈x⌉ = -⌊-x⌋ y ⌊x⌋ = -⌈-x⌉.

Las desigualdades son la forma más útil de trabajar con piso y techo en demostraciones. Permiten reemplazar una expresión redondeada por límites enteros controlados.

23.7 Desplazamiento por enteros

Sumar un entero desplaza el piso y el techo en esa misma cantidad. Si k es entero, entonces:

⌊x + k⌋ = ⌊x⌋ + k.
⌈x + k⌉ = ⌈x⌉ + k.

Ejemplo: ⌊3,7 + 5⌋ = ⌊8,7⌋ = 8.
También: ⌊3,7⌋ + 5 = 3 + 5 = 8.

La condición de que k sea entero es importante. Si se suma una fracción, el resultado no puede simplificarse de esta manera en general.

23.8 Piso y techo de sumas

En general, el piso de una suma no es igual a la suma de los pisos. Sin embargo, existen cotas útiles:

⌊x⌋ + ⌊y⌋ ≤ ⌊x + y⌋ ≤ ⌊x⌋ + ⌊y⌋ + 1.

Ejemplo: x = 1,6 e y = 2,6.
⌊x⌋ + ⌊y⌋ = 1 + 2 = 3.
⌊x + y⌋ = ⌊4,2⌋ = 4.

La diferencia de a lo sumo uno se debe a que las partes fraccionarias de x e y pueden completar una unidad adicional.

23.9 División entera y resto

Para enteros a y b > 0, la división euclídea expresa a como a = bq + r, donde q es el cociente entero y 0 ≤ r < b. El cociente q es ⌊a/b⌋.

a = b⌊a/b⌋ + r, con 0 ≤ r < b.

23 = 10 · ⌊23/10⌋ + 3.
⌊23/10⌋ = 2.

Esta relación conecta piso, módulo y división entera. Es central en aritmética modular, paginación, agrupamiento y algoritmos que procesan bloques.

23.10 Paginación: uso del techo

function cantidadDePaginas(elementos, porPagina) {
  if (porPagina <= 0) throw new Error("porPagina debe ser positivo");
  return Math.ceil(elementos / porPagina);
}

console.log(cantidadDePaginas(23, 10)); // 3
console.log(cantidadDePaginas(20, 10)); // 2

El techo cuenta la última página parcial. Usar piso en este caso daría 2 páginas para 23 elementos y dejaría tres elementos sin mostrar.

23.11 Agrupar elementos en bloques

Si un procesamiento trabaja con bloques de tamaño b, el bloque que contiene al índice i, comenzando desde cero, es ⌊i/b⌋. Esta regla convierte un índice individual en un identificador de grupo.

Tamaño de bloque: 4.
Índices 0, 1, 2, 3 → bloque 0.
Índices 4, 5, 6, 7 → bloque 1.
Índice i → bloque ⌊i/4⌋.

Se usa en paginación, memoria, procesamiento por lotes, fragmentación de archivos e índices de matrices.

23.12 Calcular el bloque de un índice

function bloqueDeIndice(indice, tamanoBloque) {
  if (!Number.isInteger(indice) || indice < 0) return "índice inválido";
  return Math.floor(indice / tamanoBloque);
}

console.log(bloqueDeIndice(7, 4)); // 1
console.log(bloqueDeIndice(8, 4)); // 2

23.13 Dividir un arreglo en dos mitades

Los algoritmos divide y vencerás suelen usar piso o techo para definir tamaños enteros de subproblemas. Si un arreglo tiene n elementos, sus mitades pueden tener tamaños ⌊n/2⌋ y ⌈n/2⌉.

n = 7.
⌊7/2⌋ = 3 y ⌈7/2⌉ = 4.

Las mitades contienen 3 y 4 elementos.
Su suma es 7, por lo que no se pierde ningún elemento.

Esta distinción explica por qué las recurrencias de algoritmos reales suelen usar piso y techo aunque el análisis asintótico las simplifique a n/2.

23.14 Aplicación en búsqueda binaria

Para elegir el índice central de un intervalo entero [inicio, fin] se utiliza el piso de su promedio. De esta forma se obtiene un índice válido incluso cuando el intervalo tiene longitud par.

function indiceCentral(inicio, fin) {
  return Math.floor((inicio + fin) / 2);
}

console.log(indiceCentral(0, 6)); // 3
console.log(indiceCentral(0, 7)); // 3

En lenguajes con enteros de tamaño fijo, una implementación segura suele calcular inicio + Math.floor((fin - inicio) / 2) para evitar desbordamiento al sumar extremos grandes.

23.15 Funciones piso, techo y complejidad

En análisis asintótico, piso y techo generalmente no cambian el orden de crecimiento. Por ejemplo, ⌊n/2⌋ y ⌈n/2⌉ son ambos Θ(n).

n/2 - 1 < ⌊n/2⌋ ≤ n/2.
n/2 ≤ ⌈n/2⌉ < n/2 + 1.

Por lo tanto, ambas cantidades son proporcionales a n.

Esta propiedad permite analizar recurrencias como T(n) = 2T(⌊n/2⌋) + n sin que los redondeos oculten el orden Θ(n log n).

23.16 Errores frecuentes

  • Creer que piso elimina los decimales hacia cero para números negativos.
  • Usar piso cuando se necesita cubrir una cantidad completa y corresponde techo.
  • Olvidar validar que el divisor o tamaño de página sea positivo.
  • Suponer que ⌊x + y⌋ siempre es ⌊x⌋ + ⌊y⌋.
  • Mezclar índices que comienzan en cero con números de página que comienzan en uno.
  • Ignorar el riesgo de desbordamiento al calcular promedios de índices grandes.

23.17 Qué debes recordar

  • ⌊x⌋ es el mayor entero menor o igual que x.
  • ⌈x⌉ es el menor entero mayor o igual que x.
  • Con números negativos, piso se aleja de cero y techo se acerca a cero.
  • Piso se vincula con división entera; techo cuenta grupos o unidades necesarias.
  • Las mitades ⌊n/2⌋ y ⌈n/2⌉ preservan todos los elementos de un problema.
  • Los redondeos no cambian habitualmente el orden asintótico.

23.18 Ejercicio conceptual

Una lista tiene 57 registros y se procesan en bloques de 8. El número de bloques necesarios es ⌈57/8⌉ = 8. El último bloque contiene 1 registro; los siete bloques anteriores contienen 56.

Piso responde: ¿cuántos bloques completos hay? ⌊57/8⌋ = 7.
Techo responde: ¿cuántos bloques se necesitan para cubrir todo? ⌈57/8⌉ = 8.

23.19 Conclusión

Las funciones piso y techo conectan cantidades reales con estructuras enteras. Elegir la función correcta evita errores de límites, índices y agrupamientos, y permite escribir algoritmos que manejan correctamente divisiones no exactas.

En el próximo tema comenzaremos el estudio de la aritmética modular, basada en restos de división y esencial para ciclos, criptografía y validaciones.