Travis Brown
Travis Brown

Reputation: 139058

Interpreting unsigned integers as signed while widening

Suppose I've got a lot of values of type Word8, Word16, and Word32 lying around. I want to widen them, interpreting some as signed and some as unsigned, so that I can store them all in an [Int64]. I know I can write something like the following function, where the first argument specifies whether we want to interpret the Word8 as signed or not:

convert8 :: Bool -> Word8 -> Int64
convert8 False i = fromIntegral i
convert8 True  i = fromIntegral (fromIntegral i :: Int8)

This gives me the result I want:

*Main> convert8 False 128
128
*Main> convert8 True 128
-128

The double fromIntegral feels inelegant to me, though. Is there some nicer way to say "interpret this Word as a signed integer and stick it in a bigger Int"?

Upvotes: 4

Views: 824

Answers (1)

MathematicalOrchid
MathematicalOrchid

Reputation: 62848

From what I recall, GHC stores all integers as one machine word. (In other words, a 32-bit GHC stores integers as 32 bits. A 64-bit GHC stores them as 64 bits.) So if you request an 8-bit integer, it stores it as 32 bits anyway, but only uses the first 8 bits.

Because of this, I'm fairly sure that widening or narrowing using fromIntegral is actually no-op at run-time; all it does is change the type signature, with no run-time cost. (Converting from unsigned to signed might be doing sign extension, however. I'm not completely sure how that part works. It's probably still one machine instruction though.)

In short, I think the double fromIntegral is probably about the best way to do this. You could manually implement sign extension yourself, but the built-in machine instruction for doing this is likely to be faster.

Upvotes: 4

Related Questions