5

The Haskell base documentation says that "A Word is an unsigned integral type, with the same size as Int."

How can I take an Int and cast its bit representation to a Word, so I get a Word value with the same bit representation as the original Int (even though the number values they represent will be different)?

I can't use fromIntegral because that will change the bit representation.

I could loop through the bits with the Bits class, but I suspect that will be very slow - and I don't need to do any kind of bit manipulation. I want some kind of function that will be compiled down to a no-op (or close to it), because no conversion is done.

Motivation

I want to use IntSet as a fast integer set implementation - however, what I really want to store in it are Words. I feel that I could create a WordSet which is backed by an IntSet, by converting between them quickly. The trouble is, I don't want to convert by value, because I don't want to truncate the top half of Word values: I just want to keep the bit representation the same.

Isaac van Bakel
  • 1,772
  • 10
  • 22
  • 1
    [`unsafeCoerce`](https://hackage.haskell.org/package/base-4.14.0.0/docs/Unsafe-Coerce.html#v:unsafeCoerce) seems to do the trick actually, but I'm not sure it's to be trusted. – leftaroundabout Sep 24 '20 at 14:09
  • 1
    The documentation for [`unsafeCoerce#`](https://hackage.haskell.org/package/base-4.14.0.0/docs/GHC-Exts.html#v:unsafeCoerce-35-) suggests that it can be (since casting between same-size unboxed types is supported). I do prefer `int2Word#` and `word2Int#` for being more explicit, though - better to have the compiler's vocal support. – Isaac van Bakel Sep 24 '20 at 14:29
  • 2
    Are you sure that `fromIntegral` changes the bit representation? For example, when I use ghci to run `fromIntegral (2147483648 :: Word32) :: Int32`, it returns `-2147483648`, which is the correct equivalent bit representation. – Louis Wasserman Sep 24 '20 at 21:18
  • 1
    That is a [strange implementation](https://hackage.haskell.org/package/base-4.14.0.0/docs/src/GHC.Real.html#line-401) which does indeed do bit conversion - and I confess to not having tried it, because that behaviour is completely surprising and not at all what I would expect from `fromIntegral`. – Isaac van Bakel Sep 25 '20 at 09:41
  • @IsaacvanBakel In fact, `fromIntegral :: Int -> Word` *does* preserve bit-pattern, and the same holds for `fromIntegral :: Word -> Int`. Since `fromIntegral = fromInteger . toInteger` and `Integer` has a bad representation for integers between `2^(WORD_SIZE_IN_BITS-1)< x < 2^WORD_SIZE_IN_BITS - 1`, this looks like a value conversion, but this is bit-pattern-preserving in values. To a better performance, the implementation has a GHC Rewrite Rule that replaces `fromInteger` with `int2Word#` and `word2Int#`. – gksato Mar 01 '21 at 09:41

1 Answers1

5

int2Word#/word2Int# in GHC.Prim perform bit casting. You can implement wrapper functions which cast between boxed Int/Word using them easily.

Cheng Shao
  • 66
  • 1