打字球拍的优化......这太过分了吗?

时间:2015-12-02 14:49:21

标签: optimization integer racket typed-racket

关于打字/球拍的问题。我目前正在通过Euler Project problems努力学习球拍。 my solutions中的一些非常慢,特别是在处理素数和因子时。因此,对于某些问题,我尝试制作打字/球拍版本,我发现速度没有提高,恰恰相反。 (我尝试使用非常大的数字来减少开销的影响,计算大约是10秒。)

我从Racket文档中了解到最佳优化发生when using Floats/Flonums。所以...是的,我已经尝试制作处理整数问题的浮点版本。与使用this problem使用整数的racket version一样,以及typed/racket one人工将整数转换为浮点数。我必须使用技巧:检查两个数字之间的相等性实际上意味着检查它们是否足够接近",就像在这个函数中检查x是否可以被y除以一样:

(: divide? (-> Flonum Flonum Boolean))
(define (divide? x y)
  (let ([r (/ x y)])
    (< (- r (floor r)) 1e-6)))

它有效(嗯......解决方案是正确的)我的速度提高了30%-40%。

这有多可以接受?人们真的在现实生活中这样做吗?如果没有,使用整数时优化类型/球拍解决方案的最佳方法是什么?或者在处理整数时是否应该完全放弃键入/球拍并保留浮点计算的问题?

2 个答案:

答案 0 :(得分:4)

在大多数情况下,解决方案是使用更好的算法,而不是转换为Typed Racket。

由于Project Euler的大多数问题都涉及整数,所以这里有一些提示和技巧:

  1. 除法运算符/需要计算分母和分子之间的最大公共除法,以便抵消公因子。如果您只想知道一个数字是否除以另一个数字,这会使/成为一个糟糕的选择。使用(= (remainder n m) 0)检查m是否划分n。另外:当你知道除法的余数为零时,使用quotient rander而不是/

  2. 使用memoization避免重新计算。即使用向量来存储已计算的结果。示例:https://github.com/racket/math/blob/master/math-lib/math/private/number-theory/eulerian-number.rkt

  3. 首先实现一个朴素的算法。然后考虑如何减少案件数量。经验法则:如果你能将案件数量减少到1-10万,那么蛮力最有效。

  4. 减少查找搜索空间参数化的个案数量。示例:如果您需要找到毕达哥拉斯三元组:在数字m和n上循环,然后计算a = m^2 - n^2b = 2mnc = m^2 + n^2。这比循环a,b和c更快,跳过那些^ 2 + b ^ 2 = c ^ 2不成立的三元组。

  5. math/number-theory的来源中查找提示和技巧。

答案 1 :(得分:2)

由于我无法提供任何一般的提示,因此我没有想要成为一个真正的答案,因为我最近没有发布过“Amicable数字” 问题21“,我想也许在这里留下你的解决方案(遗憾的是没有很多Lisp解决方案在Euler上发布......)。

(define (divSum n)
  (define (aux i sum)
    (if (> (sqr i) n)
        (if (= (sqr (sub1 i)) n)  ; final check if n is a perfect square
            (- sum (sub1 i))
            sum)
        (aux (add1 i) (if (= (modulo n i) 0)
                          (+ sum i (/ n i))
                          sum))))
  (aux 2 1))


(define (amicableSum n)
  (define (aux a sum)
    (if (>= a n)
        sum
        (let ([b (divSum a)])
          (aux (add1 a)
               (if (and (> b a) (= (divSum b) a))
                   (+ sum a b)
                   sum)))))
  (aux 2 0))

> (time (amicableSum 10000))
cpu time: 47 real time: 46 gc time: 0

在处理除数时,通常可以使用divSum停止在n的平方根处。当你找到一个友好的对时,你也可以同时将两者加到总和中,这样可以节省你在我的代码中不必要的(divSum b)计算。