如何对 Haskell 中的整数进行 unsigned/logical 右移?

How do you do an unsigned/logical shift right on an Integer in Haskell?

shiftR in Data.Bits 对 Integers 进行算术移位。有没有一种标准的方法来正确地进行逻辑移位?

我可以想出两种方法来做到这一点。取商乘以 2^n:

unsignedShiftR i n = i `quot` (2 ^ n)

另一种方法是在算术移位后屏蔽高位 n 位(尽管我不确定您是否可以获得屏蔽的位置)。

出于某种原因,它未包含在 Data.Bits 中,但有一个 GHC primop: uncheckedIShiftRL#. Also, GHC.Base 导出更安全的版本,如 iShiftRL#:

iShiftRL# :: Int# -> Int# -> Int#
a `iShiftRL#` b | isTrue# (b >=# WORD_SIZE_IN_BITS#) = 0#
                | otherwise                          = a `uncheckedIShiftRL#` b

我们可以用不同数量的检查包装 GHC.Base 版本或 primop:

{-# LANGUAGE MagicHash #-}

import GHC.Base
import GHC.Prim

uncheckedIShiftRL :: Int -> Int -> Int
uncheckedIShiftRL (I# n) (I# i) = I# (uncheckedIShiftRL# n i)

unsafeIShiftRL :: Int -> Int -> Int
unsafeIShiftRL (I# n) (I# i) = I# (iShiftRL# n i)

iShiftRL :: Int -> Int -> Int
iShiftRL (I# n) (I# i)
  | isTrue# (i >=# 0#) = I# (iShiftRL# n i)
  | otherwise = error "shift by negative amount"

Int 而言,标准的做法是将其转换为无符号类型并将其移动到那里:

import Data.Word

ushiftR :: Int -> Int -> Int
ushiftR n k = fromIntegral (fromIntegral n `shiftR` k :: Word)