mathandtic
mathandtic

Reputation: 159

Convert Binary to Decimal Haskell

I need a program in which I enter a binary system number, and return that same number to me in decimal base.

binToDec :: Integer -> Integer

binToDec 1110101011111111000000111100001010101011110010000001 = 4134096010394753

binToDec 111111111111111111111111111111111111111111111111111111111111111 =  9223372036854775807 

I also need the examples above to be compiled in less than 5 seconds.

I have managed to do this, but the problem is that it starts from a list of integers:

binToDec l = sum $ map (2^) $ findIndices (==1) $ reverse l

Upvotes: 3

Views: 7482

Answers (2)

Christian Brolin
Christian Brolin

Reputation: 111

decToBin :: Integer -> Integer
decToBin = convert' 10 2

binToDec :: Integer -> Integer
binToDec = convert' 2 10

convertAny :: Integer -> Integer -> Integer -> Integer
convertAny from to = convert' 10 to . convert' from 10

convert' :: Integer -> Integer -> Integer -> Integer
convert' from to | validBase from && validBase to = go
  where
    go 0 = 0
    go k | valid = r + from * go q
         | otherwise =
           error $ "Invalid digit (" ++ show d ++ ") for base " ++ show from
       where
         valid = d < from
         d = k `mod` 10
         (q,r) = k `divMod` to
    validBase b = b >=2 && b <= 10
convert' _ _ = error "Bases must be between 2 and 10.

Upvotes: 0

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476493

Given the "decimal" number only contains zeros and ones, we can use recursion for this:

bintodec :: Integral i => i -> i
bintodec 0 = 0
bintodec i = 2 * bintodec (div i 10) + (mod i 10)

So what we do here is using div i 10 to "shift the number one to the right". We use recursion and multiply with two to use binary representation. We also use mod i 10 to obtain the last digit that we then add to the number.

As said before this is not very safe, since for instance it will also produce a number for bintodec 10010202010, we can in that case return a Maybe i with:

bintodec :: Integral i => i -> Maybe i
bintodec 0 = Just 0
bintodec i | last < 2 = fmap (\x -> 2*x + last) (bintodec (div i 10))
           | otherwise = Nothing
    where last = mod i 10

This then produces:

Prelude> bintodec 1110101011111111000000111100001010101011110010000001
Just 4134096010394753
Prelude> bintodec 11101010111111110000001111000010101014011110010000001
Nothing

It is however better to use a [Bool] for instance, since this will enforce that we can not provide a value that is not a valid bitstring. In that case we can use:

bintodec :: [Bool] -> Int
bintodec = foldr (\x y -> fromEnum x + 2*y) 0

Upvotes: 4

Related Questions