StackOverFlow在计算数字时

时间:2010-01-21 18:41:02

标签: clojure

我正在尝试计算Clojure中数字的位数,如下所示:即使是2位数字,我也会得到StackOverflowError

(defn num-digits [n]
   (if (= 0 n)
   0
   (inc (num-digits (/ n 10)))))
(println (num-digits 93))

但是如果我用/ unchecked-divide替换/那么它至少可以工作93.但是这两种技术都不适用于:

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

首先,我想知道如何在Clojure中执行C风格的划分。每当我做(/ x y)时,我得到一个比率而不是一个整数。这样做的方法是什么?

其次,是否有一种方法可以将此数字转换为数字向量和调用计数。

谢谢,
Ajay G

4 个答案:

答案 0 :(得分:8)

这就是你遇到问题的原因:

user> (take 10 (iterate #(/ % 10) 10923))

(10923 10923/10 10923/100 10923/1000 10923/10000 10923/100000 10923/1000000 10923/10000000 10923/100000000 10923/1000000000)

这是修复:

user> (take 10 (iterate #(quot % 10) 10923))

(10923 1092 109 10 1 0 0 0 0 0)

这是您正在寻找的表达方式:

user> (count (take-while #(not (zero? %)) (iterate #(quot % 10) 10923)))
5

这是作弊:

user> (count (str 10923))
5

这是你试图编写的函数(但是小心,它会为大数字堆栈溢出):

user> (defn num-digits [n]
        (if (= 0 n)
          0
          (inc (num-digits (quot n 10)))))

#'user/num-digits
user> (num-digits 10923)
5

但是,它取决于挑战:

user> (num-digits 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000)

158

该函数的这个版本不会破坏堆栈:

user> (defn num-digits-tail-recursion 
        ([n count]
           (if (= 0 n)
             count
             (recur (quot n 10) (inc count))))
        ([n] (num-digits-tail-recursion n 0)))
#'user/num-digits-tail-recursion
user> (num-digits-tail-recursion 10923)
5

所有版本都以自己的方式感兴趣。好问题!

答案 1 :(得分:4)

Clojure中没有尾调用优化。您必须使用recur特殊表单。

E.g:

(defn num-digits [n]
  (loop [n n
         cnt 0]
    (if (= 0 n)
      cnt
      (recur (quot n 10) (inc cnt)))))

但在回答你的第二个问题时:是的,这就是:

(defn num-digits [n] (count (str n)))

答案 2 :(得分:3)

根据this page,您可以使用quot在Clojure中执行整数除法:

(quot n 10)

答案 3 :(得分:3)

Clojure试图通过数字操作“做正确的事”并且永远不会失去精确度。所以当你的设备说17/10时,结果是17/10(十七分之十)的分数不是1.默认情况下,任何数值运算都不会丢失任何信息。在这种情况下,你可以使用(quote x 10)显式地抛弃额外的精度,或者你可以将结果转换为int (int (/ 17 10))

对于第二个问题,这里有点破解:

(count (str 257))

防止在Clojure中使用递归来阻止堆栈的一个好方法是使用其他更高阶函数而不是递归。

(count (take-while pos? (iterate #(quot % 10) 257))))