2009-12-24 50 views
54

Cómo imprimir literales enteros en binario o hexadecimal en haskell?Cómo imprimir literales enteros en binario o hexadecimal en haskell?

printBinary 5 => "0101" 

printHex 5 => "05" 

¿Qué bibliotecas/funciones lo permiten?

Encontré el módulo numérico y su función showIntAtBase pero no he podido usarlo correctamente.

> :t showIntAtBase 

showIntAtBase :: (Integral a) => a -> (Int -> Char) -> a -> String -> String 

Respuesta

69

El módulo numérico incluye varios functions for showing an Integral type en varias bases, incluyendo showIntAtBase. Estos son algunos ejemplos de uso:

import Numeric (showHex, showIntAtBase) 
import Data.Char (intToDigit) 

putStrLn $ showHex 12 "" -- prints "c" 
putStrLn $ showIntAtBase 2 intToDigit 12 "" -- prints "1100" 
+6

Para cualquier persona perezosa como yo que no se desplazó hacia abajo, el ejemplo de printf es mucho más conciso y flexible, y puede hacer otras cosas útiles, como p. Ej. dar una cadena de longitud constante y todas las demás características de printf. En lugar de arriba, solo: 'printf"% 032b "5' – mozboz

+11

@mozboz,' printf' en Haskell es más como un truco de magia que una función para ser usado en código serio. La cadena de formato se analiza en tiempo de ejecución (lo que puede producir errores de tiempo de ejecución) y todo el mecanismo es un poco lento. – dfeuer

+0

Éste no funciona con números negativos. – CMCDragonkai

3

Puede convertir número entero a binario con algo como lo siguiente:

uso
decToBin x = reverse $ decToBin' x 
    where 
    decToBin' 0 = [] 
    decToBin' y = let (a,b) = quotRem y 2 in [b] ++ decToBin' a 

en GHCi:

Prelude> decToBin 10 
[1,0,1,0] 
+0

¿No sería mejor tener b: (decToBIn a) al final de la última línea? – prince

+0

¿No debería devolver 0? 'decToBin '0 = [0]' ¿quizás? – Jaseem

+0

@SjB, no funciona para números negativos –

26

Si importa los módulos Numeric y Data.Char, usted puede hacer esto:

showIntAtBase 2 intToDigit 10 "" => "1010" 
showIntAtBase 16 intToDigit 1023 "" => "3ff" 

Esto funciona para cualquier base de hasta 16, ya que esto es todo lo que intToDigit trabaja para. El motivo del argumento de cadena vacía adicional en los ejemplos anteriores es que showIntAtBase devuelve una función de tipo ShowS, que concatenará la representación de visualización en una cadena existente.

24

También puede utilizar printf del paquete printf para formatear la salida con formato de estilo c descriptores:

import Text.Printf 

main = do 

    let i = 65535 :: Int 

    putStrLn $ printf "The value of %d in hex is: 0x%08x" i i 
    putStrLn $ printf "The html color code would be: #%06X" i 
    putStrLn $ printf "The value of %d in binary is: %b" i i 

Salida:

El valor de 65535 en hexadecimal es: 0x0000FFFF
El El código de color html sería: # 00FFFF
El valor de 65535 en binario es: 1111111111111111

+0

'printf" El valor de% d en hex es: 0x% 08x "i i' está bien porque printf puede ser tanto 'IO()' como 'String' – Nybble

+0

Sí, de hecho. Solo quería que fuera obvio, que se puede usar como una función pura que devuelve un String. –

4

hexagonal se puede escribir con 0x y binario con 0b prefijo ej .:

> 0xff 
255 
>:set -XBinaryLiterals 
> 0b11 
3 

Tenga en cuenta que la extensión binario requiere BinaryLiterals.

2

Se podría definir sus propias funciones recursivas como:

import Data.Char (digitToInt) 
import Data.Char (intToDigit) 

-- generic function from base to decimal 
toNum :: [Char] -> Int -> (Char -> Int) -> Int 
toNum [] base map = 0 
toNum s base map = base * toNum (init(s)) base map + map(last(s)) 

-- generic function from decimal to base k 
toKBaseNum :: Int -> Int -> (Int -> Char) -> [Char] 
toKBaseNum x base map | x < base = [map x] 
         | otherwise = toKBaseNum (x `div` base) base map ++ [map(x `mod` base)] 


-- mapping function for hex to decimal 
mapHexToDec :: Char -> Int 
mapHexToDec x | x == 'A' = 10 
       | x == 'B' = 11 
       | x == 'C' = 12 
       | x == 'D' = 13 
       | x == 'E' = 14 
       | x == 'F' = 15 
       | otherwise = digitToInt(x) :: Int 

-- map decimal to hex 
mapDecToHex :: Int -> Char 
mapDecToHex x | x < 10 = intToDigit(x) 
       | x == 10 = 'A' 
       | x == 11 = 'B' 
       | x == 12 = 'C' 
       | x == 13 = 'D' 
       | x == 14 = 'E' 
       | x == 15 = 'F' 

-- hex to decimal 
hexToDec :: String -> Int 
hexToDec [] = 0 
hexToDec s = toNum s 16 mapHexToDec 

-- binary to decimal 
binToDec :: String -> Int 
binToDec [] = 0 
binToDec s = toNum s 2 (\x -> if x == '0' then 0 else 1) 

-- decimal to binary 
decToBin :: Int -> String 
decToBin x = toKBaseNum x 2 (\x -> if x == 1 then '1' else '0') 

-- decimal to hex 
decToHex :: Int -> String 
decToHex x = toKBaseNum x 16 mapDecToHex 

Explicación: Como se puede ver, el función toNum convierte un valor basado en k a decimal, utilizando la base dada y una función de mapeo . La función de mapeo mapeará caracteres especiales a un valor decimal (por ej. A = 10, B = 11, ... en hexadecimal). Para el mapeo binario también puedes usar una expresión lambda como la que ves en binToDec.

Considerando que la función toKBaseVal es lo contrario, convirtiendo un valor decimal en un valor k.Nuevamente, necesitamos una función de mapeo que haga lo contrario: de un decimal al carácter especial correspondiente del valor basado en k.

Como prueba puede escribir:

binToDec(decToBin 7) = 7 

Supongamos que desea convertir de decimal a octal:

-- decimal to octal 
decToOct :: Int -> String 
decToOct x = toKBaseNum x 8 (\x -> intToDigit(x)) 

Una vez más, yo uso sólo una expresión lambda, porque la asignación es simple: solo int a digit.

Espero que ayude! Buena programación!

Cuestiones relacionadas