在Haskell中将十进制转换为二进制

时间:2016-10-20 22:48:51

标签: haskell recursion binary

我发现这段代码有效,但我不明白为什么会这样。它将Int转换为二进制表示。

repBinario::Int -> Int
repBinario 0 = 0
repBinario x = 10 * repBinario (x `div` 2) + x `mod` 2

我知道divmod做了什么。但是,它如何将mod的每个数字放在一起?

3 个答案:

答案 0 :(得分:6)

简而言之,它在每次迭代时将累计结果乘以10

为了更清楚地了解正在发生的事情,我们可以将您的功能划分为两个更简单的功能。第一个将整数转换为二进制数字列表。然后另一个将完成困扰你的事情:将二进制数字列表连接成一个整数。

extractBinDigits :: Int -> [Int]
extractBinDigits =
  unfoldr (\x -> if x == 0 then Nothing else Just (mod x 2, div x 2))

concatDigits :: [Int] -> Int
concatDigits =
  foldr (\a b -> a + b * 10) 0

如您所见,我们只需将每个步骤上的累加器乘以10,然后将每个数字添加到其中。

然后你原来的功能变成了这个:

repBinario :: Int -> Int
repBinario =
  concatDigits . extractBinDigits

现在,我们可以检查和重复使用我们程序中更精细的部分,为我们提供更大的灵活性。例如,通过添加另一个简单函数,您现在可以一次性将整数转换为字符串:

showDigits :: [Int] -> String
showDigits =
  reverse . map (chr . (+ 48))

repStringyBinario :: Int -> String
repStringyBinario =
  showDigits . extractBinDigits

答案 1 :(得分:5)

我们来看一个例子,然后:

repBinario 5

repBinario 5的替代定义:

10 * repBinario (5 `div` 2) + 5 `mod` 2

减少divmod

10 * repBinario 2 + 1
                    ^

我们在这里制作了第一个数字,标有^

repBinario 2的替代定义:

10 * (10 * repBinario (2 `div` 2) + 2 `mod` 2) + 1
                                                 ^

减少divmod

10 * (10 * repBinario 1 + 0) + 1
                          ^    ^

repBinario 1的替代定义:

10 * (10 * (10 * repBinario (1 `div` 2) + 1 `mod` 2) + 0) + 1
                                                       ^    ^

减少divmod

10 * (10 * (10 * repBinario 0 + 1) + 0) + 1
                                ^    ^    ^

repBinario 0的替代定义:

10 * (10 * (10 * 0 + 1) + 0) + 1
                     ^    ^    ^

减少

101

在每一步中,(`mod` 2)获得最不重要的二进制数字,(`div` 2)将数字向右移动,丢弃该数字并将其余数字递归传递给{ {1}}。最后,我们执行相反的过程:divBinario将当前数字添加到结果中,(+ d)将数字向左移动,以便我们可以添加更多数字。

你得到的是一个十进制数,看起来与原始输入的二进制表示相同。

如果您按(* 10)移除乘法,则会得到10,这是一个为您提供数字的人口数的函数 - popCount的数量二进制表示中的位:

1

答案 2 :(得分:5)

我认为最好手动计算一个小值的这个函数 - 这是可能的,因为这是一个纯函数,因此你可以用它的定义(即右边)取代左手边 - 花哨的计算机科学这个特征的词是“参照透明度”。

repBinario 24 = 10 * repBinario (24 `div` 2) + 24 `mod` 2
              = 10 * repBinario 12 + 0
              = 10 * (10 * repBinario (12 `div` 2) + 12 `mod` 2)
              = 100 * repBinario 6 + 0
              = 100 * (10 * repBinario (6 `div` 2) + 6 `mod` 2)
              = 1000 * repBinario 3 + 0
              = 1000 * (10 * repBinario (3 `div` 2) + 3 `mod` 2)
              = 10000 * repBinario 1 + 1000 * 1
              = 10000 (10 * repBinario (1 `div` 2) + 1 `mod` 2) + 1000
              = 10000 (10 * repBinario 0 + 1) + 1000
              = 10000 (10 * 0 + 1) + 1000
              = 10000 * 1 + 1000
              = 11000

在这些步骤中,我只是根据其定义评估函数,并使用整数加法/乘法服从分布律的事实。