将二进制转换为负二进制

时间:2015-11-08 10:06:25

标签: haskell binary

我需要将正二进制转换为负二进制。 我的方法似乎有些不对劲。将元素添加到列表末尾也不起作用。请帮帮我!

twoComplement :: [Int] -> [Int]
twoComplement (x:xs)    | (x:xs) == [] = [x]
                    | last (x:xs) == 0 = (twoComplement (init (x:xs))) ++ [1]
                    | last (x:xs) == 1 = (twoComplement (init (x:xs))) ++ [0]

你看,我是哈斯凯尔的新手。

2 个答案:

答案 0 :(得分:2)

Wikipedia上看,有关于如何执行二次补码转换“从LSB到MSB”的解释:

  

从LSB到MSB工作:

     

将二进制数手动转换为二进制补码的快捷方式是从最低有效位(LSB)开始,并复制所有零(从LSB向最高有效位工作),直到达到第一个1;然后复制1,并翻转所有剩余的位。

该算法非常巧妙地转换为Haskell:

twosComplement :: [Int] -> [Int]
twosComplement bs = zs ++ fixup rest
  where
    (zs, rest) = span (== 0) bs

    fixup [] = []
    fixup (x:xs) = x : map (1-) xs

此实现使用@chi在其答案中建议的小端格式:通常,这是您在处理二进制数时要使用的格式。如果确实希望将其保留为大端格式,那么您必须在应用上述定义的twosComplement之前和之后撤消该数字。

实施说明

  • span用于获取所有连续的最不重要的零(zs)以及该数字的rest
  • fixup复制遇到的第一个1(如果它存在的话,它将位于rest的头部),然后反转其余的数字。

答案 1 :(得分:1)

(x:xs) == []始终为false:第一个是包含至少一个元素(x)的列表,第二个是空的。

也许你想写类似

的东西
twoComplement [x] = [x]
twoComplement (x:xs)| last (x:xs) == 0 = (twoComplement (init (x:xs))) ++ [1]
                    | last (x:xs) == 1 = (twoComplement (init (x:xs))) ++ [0]

但这看起来仍然不对劲。

我会定义一个函数来先反转一下

invertBit :: Int -> Int
invertBit 0 = 1
invertBit 1 = 0

然后,twoComplement可以通过1)对所有列表元素应用inverBit,以及2)对刚刚获得的二进制数进行访问来完成。我为最后一个写了一个单独的函数。

使用带有最低有效位的小端符号可能也很方便 - 这简化了最后一次增量。