2014-01-28 3 views
1

Я хочу вычислить, «какую мощность числа, которую я должен использовать», с фиксированной базы, например. 2.Haskell: Преобразование Double to Int

Я хочу найти следующую (целую) мощность числа, например. 2^3 = 8 ==> get2Power 8 ==> 3.

Это просто, но get2Power 10 ==> 4 так 2^3=8 как нижняя граница и 2^4=16 как верхняя граница, я хочу, чтобы вернуть верхний один, 4.

С простой математикой Я знаю, что могу вычислить мощность с помощью некоторой функции логарифма, то есть log(x)/log(2), что приводит к удвоению. Но я хочу иметь следующий Integer.

Мой подход выглядит

get2Power :: Integer -> Integer 
get2Power x 
    | x <= 0 = -1 
    | otherwise = round (log(x)/log (2))  

которая не причина есть отсутствуют некоторые преобразования между типами. Сообщение об ошибке не помогает получить представление о том, чего я не вижу.

Может ли кто-нибудь дать мне руку помощи о том, как преобразовать результат Double в Integer/int?

ответ

3

Не используйте -1 (вы можете, но) использовать Maybe (или выбросить исключение, если вы не хотите, контроль т.е. контролируется другим способом)

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 

с другой стороны, тип входного сигнала может отличаться тип выхода (с тем же кодом тела)

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 

Примечание: поскольку мы используем Maybe (чтобы избежать плохой -1 ответа) вы должны контролировать управление потоком в вашем коде как

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!" 

наконец, если вы работаете с битами, вы можете получить, используемых битов для хранения определенного числа с помощью 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 
+0

ТНХ, BUTTTT .... Подход с usedBits звучит замечательно, но я не заинтересован в этом образце в рекурсивном решении (хотя код хорошо;)) , Код для get2Power не решает проблему с преобразованием 'Integer', а именно' 2^(get2Power 10) 'не работает, т. Е. Я не могу использовать результат get2Power для дальнейших вычислений. (Возможно, непонятно с самого начала, но ...) – LeO

+0

@LeO с вашей исходной функцией вы можете сделать '2^(get2Power (-5))', но не правильно !, вы должны узнать о 'Maybe'. Я написал пример использования: – josejuan

+0

«... мне неинтересно ... в рекурсивном решении ...», не является рекурсивным! :) – josejuan

11

Для людей, приземляется на этой странице уловляется его title "Convert Double to Int". В Haskell Prelude есть три функции, которые помогают: round, floor и ceiling.

Вот пример:

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

и обрезать :: Интеграл b => a -> b – Jorgen