Haskell: Convert Double to Int

haskell, type-conversion

Solution

Not use `-1` (you can but) use `Maybe` (or throw exception if you don't want control i.e. is controlled in other way)

get2Power :: Integral a => a -> Maybe a
get2Power x | x <= 0    = Nothing
            | otherwise = Just (ceiling (log (fromIntegral x) / log 2))

Prelude> get2Power (256 :: Int)
Just 8
it :: Maybe Integer

on the other hand, input type can be different than output type (with the same body code)

get2Power :: (Integral a, Integral b) => a -> Maybe b
              ^^^^^^^^^^^^^^^^^^^^^^
              (note how to force args to be Integral: Int, Integer, ...)

get2Power x | x <= 0    = Nothing
            | otherwise = Just (ceiling (log (fromIntegral x) / log 2))

Prelude> get2Power (2^123 :: Integer) :: Maybe Int
                          ^^^^^^^^^^^          ^^^
                          (note here how to force certain type)

Just 123
it :: Maybe Int

Note: since we are using `Maybe` (to avoid a bad `-1` response) you must control flow control in your code like

main = do
  putStrLn "Enter a number:"
  n <- readLn
  case get2Power n of
    Just k  -> putStrLn $ "2^" ++ show k ++ " is above " ++ show n
    Nothing -> putStrLn "Negative numbers not allowed!"

finally, if you are working with bits, you can get used bits to store certain number using Data.Bits

usedBits :: Bits a => a -> Int
usedBits n = length $ dropWhile not bs
             where bs = [testBit n b | b <- reverse [0..bitSize n - 1]]

Prelude Data.Bits> usedBits (256 :: Int)
9
it :: Int

Problem

I want to compute "which power of a number do I have to use" from a fixed base, e.g. 2. I want to find the next (integer) power of a number, e.g. `2 ^ 3 = 8 ==> get2Power 8 ==> 3`. This is simple, but `get2Power 10 ==> 4` since `2^3=8` as the lower bound and `2^4=16` as the upper bound I want to return the upper one, `4`. With simple math I know that I can calculate the power with some logarithm function, i.e. `log(x) / log(2)` which results in a Double. But I want to have the next `Integer`. My approach looks like ``` get2Power :: Integer -> Integer get2Power x | x <= 0 = -1 | otherwise = round (log(x) / log (2)) ``` which fails cause there is missing some conversion between the Types. The error message is not helpful to get an idea of what I'm missing. Could anybody give me a helping hand about how to transform the Double result into an Integer/int?

Original source