-- | Gray code is a binary numeral system where two successive numbers -- differ in only one bit. module Codec.Binary.Gray ( -- * List functions (for @[Bool]@) binaryToGray, grayToBinary , bitsToBinary, binaryToBits , showBinary ) where import Data.Bits (Bits, testBit, shiftR, bitSize) xor :: Bool -> Bool -> Bool xor p q = (p && not q) || (not p && q) -- | Takes a list of bits (most significant last) in binary encoding -- and converts them to Gray code. -- -- Algorithm: -- Haupt, R.L. and Haupt, S.E., Practical Genetic Algorithms, -- Second ed. (2004), 5.4. Gray Codes. binaryToGray :: [Bool] -> [Bool] binaryToGray (b:c:bs) = b `xor` c : binaryToGray (c:bs) binaryToGray [b] = [b] binaryToGray [] = [] -- | Takes a list of bits in Gray code and converts them to binary encoding -- (most significant bit last). -- -- Algorithm: -- Haupt, R.L. and Haupt, S.E., Practical Genetic Algorithms, -- Second ed. (2004), 5.4. Gray Codes. grayToBinary :: [Bool] -> [Bool] grayToBinary = foldr go [] where go c [] = [c] go c bs@(b:_) = b `xor` c : bs -- | Convert a number to a list of bits in usual binary encoding (most -- significant last). -- -- As 'bitSize', 'bitsToBinary' is undefined for types that do not -- have fixed bitsize, like 'Integer'. bitsToBinary :: (Bits b) => b -> [Bool] bitsToBinary 0 = [] bitsToBinary i | signum i == (-1) = let b = map not . bitsToBinary $ negate i - 1 in b ++ (take (bitSize i - length b) $ repeat True) -- pad major bits | otherwise = let rest = bitsToBinary $ shiftR i 1 -- works only for positive i in (testBit i 0 : rest) -- | Convert a list of bits in binary encoding to a number. binaryToBits :: (Bits a) => [Bool] -> a binaryToBits = sum . map fst . filter snd . zip (map (2^) [0..]) -- | Render a list of bits as a 0-1 string. showBinary :: [Bool] -> String showBinary [] = "0" showBinary bs = map (\b -> if b then '1' else '0') . reverse $ bs