【问题标题】:Logarithm in functional language with addition and multiplication only函数语言中的对数,仅加法和乘法
【发布时间】:2012-12-25 10:15:50
【问题描述】:

在学习考试时,我刚刚在练习中发现了以下任务:

编写一个函数,将整数对数以 2 为底(向上取整),同时仅使用乘法和加法。

我立即尝试,但无法找到任何解决方案。我认为这将是一件容易的事,但我只能在使用整数除法时找到解决方案(例如在 Haskell 中):

log2 :: Int -> Int
log2 1 = 0
log2 2 = 1
log2 x = 1 + log2 (x `div` 2)

这个任务只用乘法就可以完成吗?在左侧(模式)上使用乘法总是会导致编译器错误。并在右侧使用它,我如何将解决方案追溯到较小的数字?

【问题讨论】:

  • 您可以使用加法、乘法和<= 来实现。此外,在该示例中,您对 2 的情况是多余的。
  • 除法是乘法
  • 但我必须使用Ints,没有分数。

标签: haskell functional-programming logarithm


【解决方案1】:

并且在右侧使用它,我怎样才能将解决方案追溯到较小的数字?

递归。由于计算下限更容易,我们使用以下事实:

ceiling (log_2 n) == floor (log_2 (2*n-1))

很容易看出。然后为了找到以b 为底的对数,我们计算以 为底的对数并调整:

log2 :: Int -> Int
log2 1 = 0
log2 2 = 1
log2 n
    | n < 1     = error "Argument of logarithm must be positive"
    | otherwise = fst $ doLog 2 1
      where
        m = 2*n-1
        doLog base acc
            | base*acc > m = (0, acc)
            | otherwise = case doLog (base*base) acc of
                            (e, a) | base*a > m -> (2*e, a)
                                   | otherwise  -> (2*e+1,a*base)

需要更多步骤的更简单算法是简单地迭代,在每个步骤中乘以 2,然后计数,直到达到或超过参数值:

log2 :: Int -> Int
log2 n
    | n < 1     = error "agument of logarithm must be positive"
    | otherwise = go 0 1
      where
        go exponent prod
            | prod < n  = go (exponent + 1) (2*prod)
            | otherwise = exponent

【讨论】:

  • doLog :: (Num a) =&gt; a -&gt; a -&gt; (a, a) 或类似的东西。你不应该将它投射到log2 n | otherwise 案例中吗? ;)
  • 啊,忘了fst,谢谢。由于顶级签名,它是doLog :: Int -&gt; Int -&gt; (Int,Int),但当然它也可以多态工作。
  • 当然。不过,这将要求您明确传递 m
  • @Tinctorius 如果n :: t 代表一些(Ord t, Num t),那么m :: tbase, acc :: t。如果log2a -&gt; r 类型调用,则doLog 从守卫那里继承a -&gt; a -&gt; (b, a) 类型,不需要m 的任何传递。
  • @MarcoW。我想这已经很简单了。当然你可以有一个更简单和更慢的算法。没问题,我加一个。
【解决方案2】:

怎么样:

log2 n = length (takeWhile (<n) (iterate (*2) 1))

?

我假设您可以使用 Prelude 中的函数(如 errorfst 和比较运算符)。如果考试中不允许这样做,理论上您可以使用lengthtakeWhileiterate 的定义,并最终得到与丹尼尔的答案相对接近的东西(在精神上,可能不是在信中!)。

【讨论】:

  • 感谢您提供这个超短的替代方案!
【解决方案3】:

也许您可以使用级数展开来近似对数函数。尤其是Taylor’s ones

【讨论】:

  • 谢谢!我想不需要那么复杂,只需要一些基本的列表操作。
猜你喜欢
  • 1970-01-01
  • 2012-03-15
  • 1970-01-01
  • 2020-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多