Haskell logbase错误

问题描述 投票:7回答:3

我试图计算Haskell中Integer的长度,使用长度等于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的正确日志值?

haskell logarithm rounding-error
3个回答
4
投票

GHC模块中有一个整数对数基函数,其类型为Integer -> Integer -> Int#

用法示例:

{-# 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
投票

如果你不需要Double浮动精度,那么使用Float类型,它似乎很好。如logBase 10 (1000 :: Float)将返回3.0或功能logBase 10 . (fromInteger :: Integer -> Float) $ 1000将做同样的事情。

根据你的代码,toInteger似乎是多余的,因为truncate :: (Integral b, RealFrac a) => a -> b已经完成了这项工作。所以可能只是喜欢

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

这将正常工作到9999987。


0
投票

你不能去

amountOfDigits = length . show

(如果你只对传统基数10的数字感兴趣)

© www.soinside.com 2019 - 2024. All rights reserved.