我在以下函数中遇到数字换行问题:
f :: Word8 -> Word8 -> Word8
f a b = (a + b) `mod` 255
这个想法是将两个数字加在一起,模数255(注意 255 ,而不是mod 256 )。
显然,f 252 8
的答案应该是260 mod 255 = 5,但上面的函数实际上返回4,因为Word8
能够仅保留数字,因此252 + 8包裹到4 255.永远不会应用mod函数。
我试过了:
f :: Word8 -> Word8 -> Word8
f a b = (fromIntegral a + fromIntegral b) `mod` 255
认为它会隐式转换为Integer
或Int
,但事实并非如此。什么是正确的解决方案,以便f
不会受到包装问题的困扰并且效率不高?
答案 0 :(得分:5)
由于您要求它返回Word8
,我们可以推断mod
的参数都是Word8
,因此+
的参数两者都是Word8
' s,因此fromIntegral
实际上被推断为类型Word8 -> Word8
- 可能不是你想要的!
一种解决方法是暂时转换为Integer
(或其他任何类型),然后返回Word8
:
f a b = fromInteger ((fromIntegral a + fromIntegral b) `mod` 255)
另一个解决方案是手动检查是否发生了溢出。
f a b = (sum + if sum < a then 1 else 0) `mod` 255
where sum = a + b
(这里的最终mod操作确实是必需的,如果sum
是255
,因此没有发生溢出!)
答案 1 :(得分:1)
如果需要,可以深入研究低级Haskell并使用原始操作。我已经Michael Snoyman's answer指出了我的相关问题。在这里,我们不需要缩小结果范围,因为余数操作(remWord#
)应该始终提供足够小的数字:
{-# LANGUAGE MagicHash #-}
module Word8Mod where
import GHC.Prim
import GHC.Word
f :: Word8 -> Word8 -> Word8
f (W8# x#) (W8# y#) =
let z# = plusWord# x# y#
in W8# (remWord# z# (int2Word# 255#))