Haskell: Convert Double to Int

16,537

Solution 1

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

Solution 2

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
Share:
16,537
LeO
Author by

LeO

Updated on June 04, 2022

Comments

  • LeO
    LeO almost 2 years

    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?

  • LeO
    LeO about 10 years
    thx, BUTTTT .... The approach with the usedBits sounds great, but I am not interested for this sample in recursive solution (although the code is nice ;) ). The code for the get2Power does not solve problem with Integer conversion, namely 2^(get2Power 10) does not work, i.e. I cannot use the result of the get2Power for further computation. (Perhaps not clear from the beginning, but...)
  • josejuan
    josejuan about 10 years
    @LeO with your original function you can do 2^(get2Power (-5)), but is not correct!, you must learn about Maybe. I wrote a usage example :)
  • josejuan
    josejuan about 10 years
    "...I am not interested ... in recursive solution...", is not recursive! :)
  • leftaroundabout
    leftaroundabout about 10 years
    While Maybe is certainly a good thing to know about and quite reasonable here, I wouldn't say you must use it. For maths functions where the valid range is obvious it's generally considered ok (at least it was when the Haskell standard modules where written) to leave them as partial functions. Certainly, -1 is not an acceptable error case, but throwing an exception would be ok.
  • LeO
    LeO about 10 years
    Maybe is interesting - maybe ;) The comment from josejuan is interesting, cause in my EclipseFP-environment I get for the function defined above No instance for (Fractional Integer) rising from a use of '/' Possible fix: add an instance declaration for (Fractional Integer ... which means I cannot compile it. Seems like my real issue is somewhere else? Hints???
  • Jorgen
    Jorgen over 6 years
    and truncate :: Integral b => a -> b