总结Clojure比率很慢

时间:2017-06-26 23:16:29

标签: optimization clojure

我在Clojure中总结了一长串比率,如:

(defn sum-ratios
  [n]
  (reduce
    (fn [total ind]
      (+
        total
        (/
          (inc (rand-int 100))
          (inc (rand-int 100)))))
    (range 0 n)))

各种n的运行时间是:

  • n = 10 ^ 4 ...... 41 ms
  • n = 10 ^ 6 ...... 3.4 s
  • n = 10 ^ 7 ...... 36 s


(不太精确)替代方案是将这些值加总为双精度:

(defn sum-doubles
  [n]
  (reduce
    (fn [total ind]
      (+
        total
        (double
          (/
            (inc (rand-int 100))
            (inc (rand-int 100))))))
    (range 0 n)))

此版本的运行时为:

  • n = 10 ^ 4 ...... 8.8 ms
  • n = 10 ^ 6 ...... 350 ms
  • n = 10 ^ 7 ...... 3.4 s


为什么加总比率要慢得多?我猜测它与找到Ratios的分母的最小公倍数有关,但是有没有人知道Clojure用什么算法来比较Ratios?

1 个答案:

答案 0 :(得分:13)

让我们关注+两个Ratio时发生的情况,这是减少中每一步所发生的情况。我们从the two-arity version of +开始:

([x y] (. clojure.lang.Numbers (add x y)))

这会将我们带到Numbers.add(Obj, Obj)

return ops(x).combine(ops(y)).add((Number)x, (Number)y);

ops looks at the class of the first operand并找到RatioOps。这导致了RatioOps.add功能:

final public Number add(Number x, Number y){
    Ratio rx = toRatio(x);
    Ratio ry = toRatio(y);
    Number ret = divide(ry.numerator.multiply(rx.denominator)
            .add(rx.numerator.multiply(ry.denominator))
            , ry.denominator.multiply(rx.denominator));
    return normalizeRet(ret, x, y);
}

所以这是你的算法。此处有五个 BigInteger个操作(三个乘法,一个加法,一个除法):

(yn*xd + xn*yd) / (xd*yd)

您可以看到multiply的实施方式;它本身并不是微不足道的,你可以自己检查其他人。

果然,divide function涉及在两个数字之间找到gcd,以便可以减少:{/ p>

static public Number divide(BigInteger n, BigInteger d){
    if(d.equals(BigInteger.ZERO))
        throw new ArithmeticException("Divide by zero");
    BigInteger gcd = n.gcd(d);
    if(gcd.equals(BigInteger.ZERO))
        return BigInt.ZERO;
    n = n.divide(gcd);
    d = d.divide(gcd);
    ...
}

gcd function会创建两个新的MutableBigInteger个对象。

从计算上来说,它很昂贵,正如你从上面所能看到的那样。但是,不要忽视额外附带对象创建的成本(如上面gcd所述),因为我们涉及非缓存内存访问通常会更加昂贵。

double转换不是免费的,FWIW,it involves a division of two newly-created BigDecimals

您真的需要一个分析器才能看到完全的成本。但希望上面给出了一点背景。