LeO
LeO

Reputation: 5270

Haskell: Convert Double to Int

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?

Upvotes: 7

Views: 21953

Answers (2)

dsign
dsign

Reputation: 12710

To people that lands at this page snared by its title "Convert Double to Int". There are three functions in the Haskell Prelude that help: round, floor and ceiling.

Here is an example:

Prelude> let myFloat = 3.1415 :: Double
Prelude> let y = round myFloat :: Int
Prelude> y
3
Prelude> :type y
y :: Int

Upvotes: 32

josejuan
josejuan

Reputation: 9566

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

Upvotes: 4

Related Questions