簡體   English   中英

總結Clojure比率很慢

[英]Summing Clojure Ratios is slow

我在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秒


(不太精確)替代方案是將這些值相加為雙精度:

(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?

讓我們來看看當你+兩個Ratio s時會發生什么,這是在減少的每個步驟中發生的事情。 我們從+的兩個版本開始:

([xy] (. clojure.lang.Numbers (add xy)))

這將我們帶到Numbers.add(Obj, Obj)

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

ops 查看第一個操作數的類,並找到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)

你可以看到如何實現多重 ; 它本身並不是微不足道的,你可以自己檢查其他人。

果然, 除法函數包括找到兩個數字之間的gcd ,以便可以減少:

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函數創建兩個新的MutableBigInteger對象。

從計算上來說,它是昂貴的,正如你從上面所有的看到的那樣。 但是,不要打折額外附帶對象創建的成本(如上面的gcd ),因為我們涉及非緩存內存訪問通常會更昂貴。

double轉換不是免費的,FWIW,因為它涉及兩個新創建的BigDecimal的划分

您真的需要一個分析器來確切了解成本的位置。 但希望上面給出了一點背景。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM