你如何在 Haskell 中对整数进行无符号/逻辑移位?

jp.*_*r63 6 haskell bit-shift

shiftR在 Data.Bits 中对 进行算术移位Integers。是否有一种标准的方法来进行逻辑右移?

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

unsignedShiftR i n = i `quot` (2 ^ n)
Run Code Online (Sandbox Code Playgroud)

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

Lou*_*man 6

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

import Data.Word

ushiftR :: Int -> Int -> Int
ushiftR n k = fromIntegral (fromIntegral n `shiftR` k :: Word)
Run Code Online (Sandbox Code Playgroud)


And*_*ács 2

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

iShiftRL# :: Int# -> Int# -> Int#
a `iShiftRL#` b | isTrue# (b >=# WORD_SIZE_IN_BITS#) = 0#
                | otherwise                          = a `uncheckedIShiftRL#` b
Run Code Online (Sandbox Code Playgroud)

我们可以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"
Run Code Online (Sandbox Code Playgroud)