2.2.4.1.1. Reales a Enteros: Truncamiento o Redondeo

Como explicábamos en un capítulo anterior, la función FIX convierte los números reales a enteros a base de un simple truncamiento de la parte no entera. Este procedimiento no es satisfactorio en muchos casos donde se requiere un grado mayor de precisión. Así obtendremos el mismo resultado para (fix 6.1) que para (fix 6.9), en ambos casos simplemente 6.

Una conversión más precisa se obtiene utilizando para la conversión la función RTOS que además de convertir el número real a cadena de caracteres, es capaz, cuando se especifica cero como número de decimales, de realizar unna aproximación al entero más cercano. Así (rtos 6.1 2 0) devuelve 6 mientras que (rtos 6.9 2 0) devuelve 7.

Podemos definir una función ROUND de redondeo como sigue:

(defun round (num)
(read (rtos num 2 0))
) ;_ fin de defun

Hasta ahí bien, pero para 6.5 esta función realizaría la aproximación al entero mayor, que en este caso sería 7. Con lo que no se cumpliría la definición propuesta para la norma de Common LISP, donde se especifica que:

si el número se encuentra exactamente a mitad de camino entre dos enteros (es decir, en la forma entero + 0.5), entonces se redondea al entero par más próximo (divisible por 2). (Steele, CLTL2)

Para cumplir esta especificación deberemos desarrollar una función más compleja, que llamaremos CL-ROUND, siguiendo la norma citada.

Esta función requerirá un predicado tambén norma de Common LISP, pero ausente aún de AutoLISP-Visual LISP. El predicado EVENP que comprueba si un número entero es par.

(defun evenp (num)
(zerop (rem num 2))
) ;_ fin de defun

La nueva función cl-round recibe el número del cual comprueba:

  • si una vez redondeado el resultado NO es par (not (evenp (setq tmp (rnd num))))
  • si la parte decimal (valor absoluto) es igual a 0.5 (=(abs (rem num 1)) 0.5)

En caso de que ambas condiciones sean ciertas:

  • si el número es negativo, se le suma 1
  • si el número es positivo se le resta 1
(defun cl-round (num / tmp)
(if
(and
(not (evenp (setq tmp (rnd num))))
(= (abs (rem num 1)) 0.5)
)
(if (minusp tmp)(setq tmp (1+ tmp))(setq tmp (1- tmp)))
) ;_ fin de if
tmp
) ;_ fin de defun