Panoplia de redondeos

El redondeo de los medios puntos

El error máximo que se comete con estos redondeos a entero no es mayor que una unidad, lo cual es mucho error. Por ello, abordamos, ahora, un grupo de métodos de redondeo que mejoran el resultado final disminuyendo el error a media unidad. Aunque este no es el mayor inconveniente de los redondeos sino que la aparición de sesgos en los cálculos con grandes cantidades de números redondeados ha favorecido la definición del «redondeo de los medios puntos al par más cercano» que reduce en gran medida el sesgo en los cálculos.

En este grupo todos los números con parte decimal por debajo de \(0{,}5\) serán redondeados hacia \(\bf {-\infty} \) y los que están por encima de \(0{,}5\) se redondearán hacia \(\bf {+\infty} \). Es decir, en ambos casos se redondean al entero más próximo (Ver figura siguiente). Pero, los puntos medios de los intervalos, con parte decimal igual a \(0{,}5\), igualan las distancias a los extremos. Los siguientes métodos de redondeo se preocupan de deshacer este «empate».

El redondeo matemático que nos enseñan en la escuela redondea las mitades al extremo superior del intervalo y para redondear a un entero nos cuentan algo así  : «Si después de la coma hay un dígito 5 o mayor, se incrementa en una unidad el dígito anterior (si fuese un 9, se pondría un 0 y se incrementaría el anterior), en otro caso, dígito inferior a 5, el dígito anterior no se toca». Este redondeo es el resultado de las fórmulas equivalentes siguientes:

$$\require {AMSmath}\DeclareMathOperator{\sgn}{sgn\,}\def\smallpct{\mathbin {\small {\%}}} \left \lfloor x + 0{,}5 \right \rfloor \qquad – \left \lceil – x – 0{,}5 \right \rceil \qquad \left \lfloor \left \lceil 2 \cdot x \right \rceil / 2 \right \rfloor$$

Las variantes en los redondeos a entero dan distintas soluciones para redondear estas mitades:

  • hacia el entero superior del intervalo,
  • hacia el entero inferior del intervalo,
  • hacia el entero alejado de cero, para los negativos será el entero por debajo y para los positivos, el entero por encima.
  • hacia el entero más cercano a cero, para los negativos será el entero por encima y para los positivos, el entero por debajo.

La tabla siguiente muestra los resultados de estos redondeos para los intervalos de números negativos como \([-1, 0]\) y de positivos como \([0, 1]\): $$\small {\begin{array}{c|c|c|c|} x & -1 & \dotsb & -0{,}5 & \dotsb & 0 & \dotsb & \;0{,}5\; & \dotsb & \;1\; \\ \hline \text{entero_ms}(x) & -1 & \leftarrow & \rightarrow & \rightarrow & \;0\; & \leftarrow & \rightarrow & \rightarrow & \;1\; \\ \hdashline \text{entero_mi}(x) & -1 & \leftarrow & \leftarrow & \rightarrow & \;0\; & \leftarrow & \leftarrow & \rightarrow & \;1\; \\ \hdashline \text{entero_mlc}(x) & -1 & \leftarrow & \leftarrow & \rightarrow & \;0\; & \leftarrow & \rightarrow & \rightarrow & \;1\; \\ \hdashline \text{entero_mcc}(x) & -1 & \leftarrow & \rightarrow & \rightarrow & \;0\; & \leftarrow & \leftarrow & \rightarrow & \;1\; \\ \hline \end{array} }$$

Las definiciones Python de estos redondeos a entero son éstas:

def entero_ms(num):
    """Redondea mitades a +inf
        otros al entero más cercano.
    = -math.ceil(-num - 0.5)
    = math.floor(math.ceil(2 * num) / 2)
    = math.floor(2 * num) - math.floor(num)
    """
    return math.floor(num + 0.5)

def entero_mi(num):
    """Redondea mitades a -inf
    = - math.floor(-num + 0.5)
    """
    return math.ceil(num - 0.5)

def entero_mlc(num):
    """Redondea mitades lejos de 0 """
    return sgn(num) * math.floor(abs(num) + 0.5)

def entero_mcc(num):
    """ Redondea mitades hacia cero
    -sgn(num) * math.floor(-abs(num) + 0.5)
    """
    return sgn(num) * math.ceil(abs(num) - 0.5)

Para terminar, un último método redondea los medios puntos al número par más cercano. Esto consigue que unos sean redondeados hacia el entero superior mientras que otros lo sean al inferior. La elección se hace en función del número que precede al medio punto: los medios puntos de la forma \((impar){,}5\) se redondean a \((impar) + 1\) (es el par más cercano, dista medio punto) y los medios puntos de la forma \((par){,}5\) se redondean a \((par)\) (dista medio  punto), el resto de los números se redondean al entero más próximo. (Ver más adelante el «redondeo del banquero»)

def entero_mpar(num):
    """Redondea mitades al par más cercano,
    otros al entero más cercano.
    = round(num, 0)
    """
    return math.floor(num + 0.5) - 1 + sgn((num - 0.5) % 2)

La fórmula requiere una pequeña explicación: el resto de la división entre \(2\) (que es lo que calcula \(x \smallpct 2\)) puede ser \(0\), cuando \(x\) es número par, o \(1\) cuando \(x\) es impar. Entonces, si \(num=(par){,}5\), el resto es \(0\) ya que$$\left ( (par){,}5 -0{,}5 \right ) \smallpct 2 = (par) \smallpct 2 = 0$$ y para cualquier otro número el resto es un número positivo. Por tanto $$\sgn \left ( ((par){,}5 -0{,}5) \smallpct 2 \right ) = 0$$ y solo en este caso, en otro caso el signo es \(1\).

Ensaya cómo definir el redondeo de medios puntos al impar más cercano.

def entero_mimpar(num):
    """Redondea mitades al impar más cercano
    otros al entero más cercano
    """
    return  ¿...?     # Completa la definición

# Resultados esperados
#(10.0, 10)
#(10.25, 10)
#(10.5, 11)
#(10.75, 11)
#(11.0, 11)
#(11.25, 11)
#(11.5, 11)
#(11.75, 12)
#(12.0, 12)
#(12.25, 12)
#(12.5, 13)
#(12.75, 13)
#(13.0, 13)

Redondeo para todos

Un redondeo que afecte a algún dígito de la parte decimal de un número conserva pos decimales transformando la última cifra decimal. A la hora de hablar de redondeos, se pone más énfasis en la posición de los decimales que en el valor posicional de los dígitos. La posición decimal pos puede ser cualquier número de la secuencia \(\dots, -3, -2, -1, 0, 1, 2, 3, \dots\)

Valor de pos Redondeo a … Valor posicional
\(\phantom{-}\vdots\) \(\phantom{-}\vdots\) \(\phantom{-}\vdots\)
\(-3\) millares o
unid. de millar
\(1000 = 10^3\)
\(-2\) centenas \(100 = 10^2\)
\(-1\) decenas \(10 = 10^1\)
\(\phantom{-}0\) unidades \(1 = 10^0\)
\(\phantom{-}1\) décimas \(1/10 = 10^{-1}\)
\(\phantom{-}2\) centésimas \(1/100 = 10^{-2}\)
\(\phantom{-}\vdots\) \(\phantom{-}\vdots\) \(\phantom{-}\vdots\)

El algoritmo general redondeo() (ver más abajo) implica tres pasos:

  1. Multiplicar el número por el factor de redondeo \(10^\text{pos}\) (desplaza la coma decimal a la derecha de la posición pos), preparando el número para
  2. aplicar el metodo de redondeo a entero requerido y, finalmente,
  3. dividir por el factor de redondeo (recolocando la coma en su posición original) para conseguir el resultado.
def redondeo(num, metodo, pos=0):
    """Redondea a la posición decimal pos
    utilizando 'metodo' como función
    de redondeo a entero.
    """
    f = 10**pos
    return metodo(f * num) / f

Si el parámetro pos es 0 , como en redondeo(325.76, entero_ms, 0), o se omite, redondeo(325.76, entero_ms), el redondeo se hace a entero, 326. Pero, pos también puede ser negativo, redondeo(325.76, entero_ms, -1) es 330, redondeando a las decenas. Este algoritmo «extiende» los redondeos a entero a redondeos a cualquier posición.

Podemos truncar a cualquier posición con la expresión redondeo(num, trunca, pos)

# Usamos print(...) para presentar los resultados por pantalla
print(redondeo(325.76, trunca, -2))  # 300.0 (a las centenas)
print(redondeo(325.76, trunca, 1))   # 325.7 (a las décimas)

Redondeo escolar

Redondeo escolar

El «redondeo escolar» o matemático se refiere a redondear a una potencia de \(10\) más cercana: millares \((1000=10^3)\), centenas \((100=10^2)\), decenas \((10=10^1)\), unidades \((1=10^0)\), décimas \((0{,}1=10^{-1})\), centésimas \((0{,}01=10^{-2})\), milésimas \((0{,}001=10^{-3})\), etc. El enlace a la calculadora de redondeo te permitirá recordar el método.

def redondeo_mat(num, pos=0):
    """Es el redondeo de las matemáticas escolares"""
    f = 10**pos
    return math.floor(f * num + 0.5) / f

# Que también puede definirse como
def redondeo_mat(num, pos=0):
    f = 10**pos
    return entero_ms(f * num) / f

# Es equivalente a 
# redondeo(num, entero_ms, pos)

Redondeo del banquero

Antes de la definición del redondeo de mitades al par más cercano, los métodos redondean los medios puntos siempre en el mismo sentido (hacia arriba o hacia abajo). Cuando se realizan cálculos estadísticos (medias, desviaciones típicas, percentiles, etc.) sobre grandes cantidades de números redondeados en un mismo sentido se produce un sesgo o tendencia en los resultados. El «redondeo del banquero», que también suele llamarse redondeo del contable, viene a superar este sesgo redondeando los medios puntos unas veces hacia arriba y otras hacia abajo: quitando el medio punto e incrementando el dígito anterior solo si es impar, si es par se deja como está. (Observa la siguiente tabla de la función round()). En promedio, el \(50\%\) de las veces se incrementa y el otro \(50\%\) se deja como está.  La definición de este redondeo se apoya en el método entero_mpar() :

def redondeo_mpar(num, pos=0):
    """Redondea mitades al par más cercano"""
    f = 10**pos
    return entero_mpar(f * num) / f

# También puedes utilizar las funciones redondeo() y round()
# redondeo(num, entero_mpar, pos)
# round(num, pos)

La función round() de Python

Hasta la versión \(v2.7\) la función se comportaba exactamente igual que el redondeo matemático: los medios puntos arriba. A partir de la \(v3\) ha sido redefinida como un «redondeo del banquero». Así es como trabaja con los medios puntos: $$\small {\begin{array}{c|c|c|c|} x & -3{,}5 & -2{,}5 & -1{,}5 & -0{,}5 & 0 & \;0{,}5\; & \;1{,}5\; & \;2{,}5\; & \;3{,}5\; \\ \hline \text{round}(x) & -4 & -2 & -2 & 0 & \;0\; & 0 & 2 & 2 & \;4\; \\ \hline \end{array} }$$ El resto de valores se redondean al entero más cercano. Observa detenidamente la tabla y verás que los medios puntos se redondean al par más cercano. Cuando quieras hacer un redondeo «tradicional» de los medios puntos tendrás que utilizar la función redondeo_mat() o cualquiera de sus formas equivalentes.

Redondeo al múltiplo más cercano

Redondeo al múltiplo más cercano

Como veremos enseguida, hay muchas situaciones en las que se requiere este método. El redondeo que se hace a la centena, decena o décima más cercana, el  que se hace al cuarto de punto más cercano son todos ellos redondeos al múltiplo más cercano de un número. Desde el enlace tienes acceso a una calculadora de redondeos. ¿En qué consiste este método de redondeo? Para fijar ideas, pensemos en redondear al múltiplo de \(2\) (al par) más cercano (no confundirlo con el redondeo de mitades al par más cercano). Un número cualquiera siempre estará entre dos múltiplos consecutivos de \(2\). Observa la secuencia de transformaciones: $$\begin{array}{c}\begin{array}{c} 2  n & \dotsc & x & \dotsc & 2 (n + 1) \end{array} \\[1.2ex] \begin{array}{c} n & \dotsc & x / 2 & \dotsc & n + 1 \end{array} \\[1.2ex] \begin{array}{c} n & \dotsc & (x / 2)_r & \dotsc & n + 1 \end{array} \\[1.2ex] \begin{array}{c} 2 n & \dotsc & 2 (x / 2)_r & \dotsc & 2 (n + 1) \end{array} \end{array}$$ Dividiendo entre \(2\), conseguimos encajar \(x / 2\) entre dos enteros consecutivos \(n\) y \(n + 1\), le aplicamos un método de redondeo \( (x / 2)_r \) y regresamos al intervalo inicial multiplicando por \(2\). Sencillo, ¿no? Pues cambia el \(2\) por el número que tú quieras y tienes todo hecho para este método de redondeo.

La definición Python de este redondeo la encuentras en el código siguiente:

def redondeo_mult(k, num):
    """ Redondea al múltiplo de k más cercano. """
    return k * math.floor(num / k + 0.5)

# REDONDEOS MÁS HABITUALES...
# redondeo_mult(1000, num)  - al millar más cercano
# redondeo_mult(100, num)   - a la centena más cercana
# redondeo_mult(2, num)     - al par más cercano
# redondeo_mult(0.01, num)  - a la centésima más cercana
# redondeo_mult(0.25, num)  - al cuarto de punto más cercano
# redondeo_mult(0.125, num) - al octavo de punto más cercano

A continuación puedes ver casos reales de uso de esta modalidad de redondeo: la salida de circulación de monedas en Chile, el cálculo de interés hipotecario en España. La adopción del euro como moneda única en Europa, la reexpresión de precios en Venezuela no ejemplifican este método pero muestran que el redondeo de cantidades puede llegar a ser una preocupación nacional.

Deja una respuesta