20

I have the string "1001" and I want the string "9".

The numeric library has the (rather clunky) showIntAtBase, but I haven't been able to find the opposite.

1
  • None of these functions convert to decimal. They convert from a string representing a number in base 2 to the machine's native integer format, which, unless you are using some exotic hardware, is most assuredly a packed binary representation. It is the show function that, when applied to the integer, generates a string representing the number in base 10. Commented Sep 29, 2015 at 16:16

7 Answers 7

23

It's been a while since the original post but, for future readers' benefit, I would use the following:

import Data.Char (digitToInt)
import Data.List (foldl')

toDec :: String -> Int
toDec = foldl' (\acc x -> acc * 2 + digitToInt x) 0

No need to slow things down by using ^, reverse, zipWith, length, etc.

Also, using a strict fold reduces memory requirements.

Sign up to request clarification or add additional context in comments.

Comments

15

Here is more or less what you were looking for from Prelude. From Numeric:

(NB: readInt is the "dual" of showIntAtBase, and readDec is the "dual" of showInt. The inconsistent naming is a historical accident.)

import Data.Char  (digitToInt)
import Data.Maybe (listToMaybe)
import Numeric    (readInt)

readBin :: Integral a => String -> Maybe a
readBin = fmap fst . listToMaybe . readInt 2 (`elem` "01") digitToInt
-- readBin "1001" == Just 9

1 Comment

One can also use digitToInt = subtract (fromEnum '0') . fromEnum instead, which works for all decimal digits (the built-in implementation of digitToInt handles hexadecimal digits as well).
3

From PLEAC:

bin2dec :: String -> Integer
bin2dec = foldr (\c s -> s * 2 + c) 0 . reverse . map c2i
    where c2i c = if c == '0' then 0 else 1

1 Comment

Using a right fold forces you to reverse the intermediate list. Why not use a left fold, here, instead?
2

This helps? http://pleac.sourceforge.net/pleac_haskell/numbers.html

from the page:

bin2dec :: String -> Integer
bin2dec = foldr (\c s -> s * 2 + c) 0 . reverse . map c2i
    where c2i c = if c == '0' then 0 else 1
-- bin2dec "0110110" == 54

6 Comments

Why do they reverse and then foldr instead of foldl?
@shintoist I understand the difference. I should have said foldl'
@shintoist: Unless I'm missing something, nothing in that link suggests that foldr and reverse are preferable to foldl' here. As a matter of fact, I can only see downsides to using foldr and reverse here.
@sepp2k no, I agree, I don't see a reason either to using foldr and reverse over foldl', but I understood the question as foldr vs regular foldl.
|
1

Because

1001 = 1 * 2^0 + 0 * 2^1 + 0 * 2^2 + 1 * 2^3 = 1 + 0 + 0 + 8 = 9

┌───┬───┬───┬───┐
│1  │0  │0  │1  │
├───┼───┼───┼───┤
│2^3│2^2│2^1│2^0│
└───┴───┴───┴───┘

so obviously:

fromBinary :: String -> Int
fromBinary str = sum $ zipWith toDec (reverse str) [0 .. length str]
  where toDec a b = digitToInt a * (2 ^ b)

Comments

0
binario :: Int -> [Int]                      
binario 1 = [1]                  
binario n = binario(div x 2)++(mod n 2:[])

credits to @laionzera

Comments

0
import Control.Monad
import Data.Bits (shift)

-- Dirty version

binToInt :: String -> Int
binToInt = foldl' step 0
  where
    step acc '1' = shift acc 1 + 1
    step acc _   = shift acc 1

-- Maybe version

mayBinToInt :: String -> Maybe Int
mayBinToInt = foldM step 0
  where
    step acc '0' = pure $ shift acc 1
    step acc '1' = pure $ shift acc 1 + 1
    step acc _   = Nothing

(Of course you might want to return Nothing on empty string in the second one as well.)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.