我需要将正二进制转换为负二进制。 我的方法似乎有些不对劲。将元素添加到列表末尾也不起作用。请帮帮我!
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]
你看,我是哈斯凯尔的新手。
答案 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)对刚刚获得的二进制数进行访问来完成。我为最后一个写了一个单独的函数。
使用带有最低有效位的小端符号可能也很方便 - 这简化了最后一次增量。