首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SBCL: Fixnum优化

SBCL: Fixnum优化
EN

Stack Overflow用户
提问于 2016-11-18 15:46:01
回答 3查看 1.3K关注 0票数 4

我试图通过使用优化和修正从一个小的二次求解器中获得更快的速度。这是我的密码:

代码语言:javascript
复制
 1: (defun solve-x (d)
 2:   (declare (optimize (speed 3))
 3:               (type fixnum d))
 4:   (let ((x 1) (y 1))
 5:     (declare (type fixnum x y))
 6:     (loop while (/= (- (* x x) (* d y y)) 1) do
 7:       (if (> (- (* x x) (* d y y)) 1)
 8:         (incf y)
 9:         (incf x)))
10:     (list x y)))

SBCL编译器似乎无法正确地优化第6和第7行。我收到了很多这样的警告:

代码语言:javascript
复制
forced to do GENERIC-- (cost 10)
      unable to do inline fixnum arithmetic (cost 2) because:
      The first argument is a (INTEGER 1 21267647932558653957237540927630737409), not a FIXNUM.
      The second argument is a (INTEGER
                                -98079714615416886892398913872502479823289163909206900736
                                98079714615416886871131265939943825866051622981576163327), not a FIXNUM.
      The result is a (VALUES
                       (INTEGER
                        -98079714615416886871131265939943825866051622981576163326
                        98079714615416886913666561805061133780526704836837638145)
                       &OPTIONAL), not a (VALUES FIXNUM &REST T).
      unable to do inline (signed-byte 64) arithmetic (cost 5) because:
      The first argument is a (INTEGER 1 21267647932558653957237540927630737409), not a (SIGNED-BYTE
                                                                                         64).
      The second argument is a (INTEGER
                                -98079714615416886892398913872502479823289163909206900736
                                98079714615416886871131265939943825866051622981576163327), not a (SIGNED-BYTE
                                                                                                  64).
      The result is a (VALUES
                       (INTEGER
                        -98079714615416886871131265939943825866051622981576163326
                        98079714615416886913666561805061133780526704836837638145)
                       &OPTIONAL), not a (VALUES (SIGNED-BYTE 64) &REST T).
      etc.

不知道该在哪里继续。我已经试着在乘法、除法和减法中插入“固定值”,但它只会变得更糟。

有什么办法,怎么快点?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-11-18 18:20:10

如果您确信数字在任何时候都不会溢出,则可以将(SAFETY 0)添加到优化中。还在计算前后添加(THE FIXNUM ...),以告诉SBCL,您希望将结果作为固定值处理。三个参数*应该被分割成两个单独的调用。

您的代码目前正在循环中计算两次(- (* x x) (* d y y))。您应该将它赋值给一个变量。还请注意,由于只有XY在循环中发生了变化,所以没有必要再计算另一部分(我不知道这些计算是什么,所以我只称它们为FOOBARQUUX)。

代码语言:javascript
复制
(defun solve-x (d)
  (declare (optimize (speed 3) (safety 0) (debug 0))
           (type fixnum d))
  (let ((x 1) (y 1))
    (declare (type fixnum x y))
    (loop with foo of-type fixnum = (* x x)
          with bar of-type fixnum = (* (the fixnum (* d y)) y)
          for quux of-type fixnum = (- foo bar)
          while (/= quux 1)
          do (if (> quux 1)
                 (setf y (1+ y)
                       bar (* (the fixnum (* d y)) y))
                 (setf x (1+ x)
                       foo (* x x))))
    (list x y)))

为了避免编写两次公式,可以使用#n=读取器宏。XY也可以作为&AUX变量移到参数列表中,以摆脱LET和第二个DECLARE

代码语言:javascript
复制
(defun solve-x (d &aux (x 1) (y 1))
  (declare (optimize (speed 3) (safety 0) (debug 0))
           (type fixnum d x y))
  (loop with foo of-type fixnum = #1=(* x x)
        with bar of-type fixnum = #2=(* d (the fixnum (* y y)))
        for quux of-type fixnum = (- foo bar)
        while (/= quux 1)
        do (if (> quux 1)
               (setf y (1+ y)
                     bar #2#)
               (setf x (1+ x)
                     foo #1#)))
  (list x y))

由于XY总是增加一个,所以可以通过增加前一个值来避免某些乘法。

代码语言:javascript
复制
(defun solve-x (d &aux (x 1) (y 1))
  (declare (optimize (speed 3) (safety 0) (debug 0))
           (type fixnum d x y))
  (loop with foo of-type fixnum = 1
        with bar of-type fixnum = d
        for quux of-type fixnum = (- foo bar)
        while (/= quux 1)
        do (if (> quux 1)
               (setf bar (+ bar (the fixnum (* d y)))
                     y (1+ y)
                     bar (+ bar (the fixnum (* d y))))
               (setf foo (+ foo x)
                     x (1+ x)
                     foo (+ foo x))))
  (list x y))
票数 5
EN

Stack Overflow用户

发布于 2016-11-18 16:01:42

问题是fixnum不是一个非常有用的类型。特别是,如果abfixnum的,那么(* a b)很可能不是:考虑(* most-positive-fixnum most-positive-fixnum):这不是fixnum

因此,您需要做的是声明参数具有良好的类型:特别是那些比fixnum小得足以使算法不会溢出到bignum的类型。

票数 1
EN

Stack Overflow用户

发布于 2021-06-12 11:33:37

我不知道这些数字在您的应用程序中能得到多大,但是通过声明它们是(有符号的字节31)可以导致另一个25%的速度增益。

代码语言:javascript
复制
(deftype int31 (&optional (bits 31)) `(signed-byte ,bits))
(defun solve-x (d &aux (x 1) (y 1))
  (declare (optimize (speed 3) (safety 0) (debug 0))
           (type int31 d x y))
  (loop with foo of-type int31 = 1
        with bar of-type int31 = d
        for quux of-type int31 = (- foo bar)
        while (/= quux 1)
        do (if (> quux 1)
               (setf bar (+ bar (the int31 (* d y)))
                     y (1+ y)
                     bar (+ bar (the int31 (* d y))))
               (setf foo (+ foo x)
                     x (1+ x)
                     foo (+ foo x))))
  (list x y))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40681075

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档