2014-11-10 8 views
7

길이가 truncate (log10(x)+1)이라는 사실을 사용하여 하스켈에서 정수의 길이를 계산하려고합니다.하스켈 로그베이스 오류

사용하여 정수는 내가 만든 :

len :: Integer -> Integer 
len i = toInteger (truncate (logBase 10 (fromIntegral i)) + 1) 

불행하게도, 모든 숫자가 올바른 길이를 얻을 수 없습니다. 나는 몇 가지 경우를 시도하고 있음을 발견

logBase 10 10   = 1.0 
logBase 10 100  = 2.0 
logBase 10 1000  = 2.9999..6 
logBase 10 10000  = 4.0 
logBase 10 100000  = 5.0 
logBase 10 1000000 = 5.9999999 

이유 logBase 10 1000 3.0을 반환하지 않는 이유가 있습니까? 어떻게 기본 10에서 1000에 대한 올바른 로그 값을 얻습니까?

+0

'logBase'과 같이 정의된다'로그 Y/x' 로그; '로그'가 (반올림과 관련하여) 정확할지라도, 그 부서는 아마 범인 일 것이다. –

+0

@BartekBanachewicz 올바른 결과를 얻을 방법이 없습니까? (로그 1000)/(로그 10)을 사용해 보았지만 여전히 2.99996입니다. 로그 값은 1000에서 10까지 반 내림 할 수 있으므로 3보다 약간 작습니다. – Pphoenix

+1

'log'가 필요 없다고 가정하면 10으로 나누는 부동 소수점 연산을 피할 수 있습니다 (더 높은 전력 10). – kennytm

답변

4

유형이 Integer -> Integer -> Int# 인 GHC 모듈에는 정수 로그 기반 함수가 있습니다.

사용 예제 :

{-# LANGUAGE MagicHash #-} 

import Control.Monad 
import GHC.Integer.Logarithms (integerLogBase#) 
import GHC.Exts (Int(..)) 

main = do 
    forM_ [(1::Int)..20] $ \n -> do 
    let a = 10^n-1 
     la = I# (integerLogBase# 10 a) 
     b = 10^n 
     lb = I# (integerLogBase# 10 b) 
    putStrLn $ show a ++ " -> " ++ show la 
    putStrLn $ show b ++ " -> " ++ show lb 

출력 :

9 -> 0 
10 -> 1 
99 -> 1 
100 -> 2 
999 -> 2 
1000 -> 3 
9999 -> 3 
10000 -> 4 
99999 -> 4 
100000 -> 5 
999999 -> 5 
1000000 -> 6 
9999999 -> 6 
... 
9999999999999999999 -> 18 
10000000000000000000 -> 19 
99999999999999999999 -> 19 
100000000000000000000 -> 20 
1

당신이 다음 대신 Float 유형을 사용 Double 부동 정밀도를 필요로하지 않으며이 잘 보이는 경우. logBase 10 (1000 :: Float)과 같은 것은 3.0을 반환하거나 기능적으로는 같은 것을 할 것입니다.

toIntegertruncate :: (Integral b, RealFrac a) => a -> b이 이미 해당 작업을 수행 한 이후로 중복되는 것으로 보입니다. 그래서 간단하게 작동합니다

len :: Integer -> Integer 
len = (+1) . truncate . logBase 10 . (fromIntegral :: Integer -> Float) 

이 같이 할 수 올바르게 9999987.까지