shiftR в Data.Bits выполняет арифметический сдвиг для Integers. Есть ли стандартный способ правильно выполнить логический сдвиг?

Я могу придумать два способа сделать это. Возьмите частное на 2 ^ n:

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

Другой способ - замаскировать верхние n бит после арифметического сдвига (хотя я не уверен, что вы можете получить позицию для маски).

7
jp.rider63 5 Мар 2015 в 08:57

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

Мы можем обернуть либо версию GHC.Base, либо примоп с различным количеством проверок:

{-# 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"
2
András Kovács 5 Мар 2015 в 07:40

Что касается Int, стандартный способ сделать это - преобразовать его в беззнаковый тип и сдвинуть его туда:

import Data.Word

ushiftR :: Int -> Int -> Int
ushiftR n k = fromIntegral (fromIntegral n `shiftR` k :: Word)
5
Louis Wasserman 5 Мар 2015 в 19:19