Si alguna vez se encontraron en la necesidad de convertir un número decimal a binario y viceversa, se habrán dado cuenta que Oracle no incluye una función para poder realizarlo fácilmente.
Solamente existe la función "bin_to_num", la cual tiene el siguiente funcionamiento:
BIN_TO_NUM( expr1, expr2, ... expr_n)
Donde expr1, expr2, ... expr_n deben ser "0" o "1".
Es por esto que decidí crear las siguientes funciones:
"FNC_NUMBER_TO_BINARY" y "FNC_NUMBER_FROM_BINARY".
Para hacerlo me basé en unas funciones que encontré en este link, pero corrigiéndoles algunas cosas que no funcionaban adecuadamente.
El código
La función "FNC_NUMBER_TO_BINARY" es así:
CREATE OR REPLACE FUNCTION FNC_NUMBER_TO_BINARY ( p_numero IN NUMBER ) RETURN NUMBER IS l_max NUMBER; l_resultado NUMBER := ABS ( p_numero ); l_binario VARCHAR2(4000) := '0'; l_signo NUMBER; BEGIN -- ----------------------------------------------------- -- Determinar la cantidad de dígitos del número binario -- ----------------------------------------------------- l_max := FLOOR ( LN ( ABS ( p_numero ) ) / LN(2) ); -- ----------------------------------------------------- -- Determinar el signo -- ----------------------------------------------------- IF p_numero >= 0 THEN l_signo := 1; ELSE l_signo := -1; END IF; -- ----------------------------------------------------- -- Procesar número hasta obtener binario de l_max dígitos -- ----------------------------------------------------- FOR i IN REVERSE 0..l_max LOOP -- ----------------------------------------------------- -- Si el número parcial es mayor al dígito correspondiente -- ----------------------------------------------------- IF l_resultado >= POWER ( 2, i ) THEN -- ----------------------------------------------------- -- Agregar un '1' al final del binario -- ----------------------------------------------------- l_binario := l_binario || '1'; -- ----------------------------------------------------- -- Restar del resultado parcial el dígito correspondiente -- ----------------------------------------------------- l_resultado := l_resultado - POWER ( 2, i ); ELSE -- ----------------------------------------------------- -- En caso de que el número parcial sea menor al dígito -- correspondiente, agregar un '0' al final del binario -- ----------------------------------------------------- l_binario := l_binario || '0'; END IF; END LOOP; -- ----------------------------------------------------- -- En caso de que el número original sea potencia de dos -- lo trato en forma separada -- ----------------------------------------------------- IF ABS (p_numero) = POWER ( 2, l_max + 1) THEN l_binario := '1'; -- ----------------------------------------------------- -- Completar con '0' a la derecha hasta formar el número -- binario -- ----------------------------------------------------- FOR i IN 1..l_max + 1 LOOP l_binario := l_binario || '0'; END LOOP; END IF; -- ----------------------------------------------------- -- Retornar el número obtenido multiplicado por -- el signo correspondiente -- ----------------------------------------------------- RETURN TO_NUMBER ( l_binario ) * l_signo; END FNC_NUMBER_TO_BINARY;
Nota: Cabe aclarar que la función toma la parte entera del número que se le pase a la misma.
Y por último adjunto el código de "FNC_NUMBER_FROM_BINARY":
CREATE OR REPLACE FUNCTION FNC_NUMBER_FROM_BINARY ( p_numero IN NUMBER ) RETURN NUMBER IS l_posicion NUMBER := 0; l_binario VARCHAR2(4000); l_resultado NUMBER := 0; l_signo NUMBER; BEGIN -- ----------------------------------------------------- -- Si el número recibido es nulo, retornar -1 -- ----------------------------------------------------- IF p_numero IS NULL THEN RETURN -1; END IF; -- ----------------------------------------------------- -- Quedarse con el valor entero, sin espacios, del -- número recibido -- ----------------------------------------------------- l_binario := LTRIM ( RTRIM ( TO_CHAR ( ABS ( p_numero ) ) ) ); -- ----------------------------------------------------- -- Determinar el signo -- ----------------------------------------------------- IF p_numero >= 0 THEN l_signo := 1; ELSE l_signo := -1; END IF; -- ----------------------------------------------------- -- Procesar uno por uno los caracteres del binario -- y sumarlos al número a devolver -- ----------------------------------------------------- FOR i IN 1..LENGTH ( l_binario ) LOOP l_resultado := l_resultado + ( SUBSTR ( l_binario, i, 1 ) * POWER ( 2, LENGTH ( l_binario ) - i ) ); END LOOP; -- ----------------------------------------------------- -- Retornar el número obtenido multiplicado por -- el signo correspondiente -- ----------------------------------------------------- RETURN l_resultado * l_signo; END FNC_NUMBER_FROM_BINARY;
La ejecución
Podemos probar las funciones de la siguiente manera:
SELECT FNC_NUMBER_TO_BINARY(8) FROM dual;
SELECT FNC_NUMBER_FROM_BINARY(00001000) FROM dual;
Conclusión
Con estas dos funciones podemos realizar las conversiones que precisemos entre números decimales y binarios.
Les dejo el link por si las quieren descargar, son dos archivos .sql: [download id="11"]
Espero sus comentarios!
Excelentes funciones :).
Yo estaba trabajando con BIN_TO_NUM, pero era un fastidio tener que pasarle un arreglo de valores :s.
Perfecto!!!!!!!
Como seria para convertir a Hexadecimales????
Gracias
Julio, en este caso no te servirían estas funciones y deberías hacer unas nuevas… Si las llegás a desarrollar y las querés compartir contactame que las subimos. Gracias!
De verdad que ayuda mucho; muchas gracias.
Sólo un detalle muy importante en la parte de manejo de números negativos. El complemento a 2 brilló por su ausencia.
Si queremos tener una función realmente genérica, habría que agregarlo, no basta con una multiplicación por “-1″ X-D
Saludos
Tenés razón! Yo cuando la hice no la necesité en negativo, por eso no me preocupé. Si la querés corregir pasámela corregida que la subimos. Gracias por el aporte!
el script es excelente, solo basta
hacerle un menu y jala de maravilla…
graciasssss