Scheme 我们能否加快这一Chez方案的微型基准? 此双循环在CHZ方案中比C++中慢50倍(编译为——优化3级< /代码>和 -O3)

Scheme 我们能否加快这一Chez方案的微型基准? 此双循环在CHZ方案中比C++中慢50倍(编译为——优化3级< /代码>和 -O3),scheme,chez-scheme,Scheme,Chez Scheme,vs #包括 #包括 #包括 #包括 typedef std::pair pr; typedef std::向量向量; 双回路(恒定矢量和a) { 双acc=0; 常数int n=a.size(); 对于(int i=0;i

vs

#包括
#包括
#包括
#包括
typedef std::pair pr;
typedef std::向量向量;
双回路(恒定矢量和a)
{
双acc=0;
常数int n=a.size();
对于(int i=0;istd::cout因此,虽然这些程序看起来确实一样,但它们却不一样。在C版本中使用的是fixnum算法,而Scheme版本使用的是标准的数字塔。要使C版本更像Scheme,请尝试使用bignum库进行计算

作为一项测试,我用
(rnrs算术flonums)
(rnrs算术fixnums)
替换了算法,它将DrRacket中的执行时间减少了一半。我希望在任何实现中都会发生同样的情况

现在,我的初始测试表明,C代码的执行速度大约是预期的25倍,而不是50倍。通过改为浮点运算,我将C代码的执行速度降低到15倍左右

我认为我可以通过使用不安全的过程来加快速度,因为Scheme确实会在运行时检查每个参数的类型,它会在每个过程之前进行操作,这在C版本中是不会发生的。作为测试,我将它改为在我的实现中使用不安全的过程,现在它只慢了10倍

希望这对Chez也有帮助:)

编辑

这是我修改过的源代码,它将速度提高了2倍:

#!r6rs
(import
 (rnrs)
 ;; import the * and + that only work on floats (which are faster, but they still check their arguments)
 (only (rnrs arithmetic flonums) fl+ fl*))


(let* ((n (* 1024 16))
       (a (make-vector n))
       (acc 0.0)) ; We want float, lets tell Scheme about that!

  ;; using inexact f instead of integer i
  ;; makes every result of cos and sin inexact
  (do ((i 0 (+ i 1))
       (f 0.0 (+ f 1)))
    ((= i n) #f)
    (vector-set! a i (cons (cos f) (sin f))))

  (do ((i 0 (+ i 1)))
    ((= i n) #f)
    (do ((j 0 (+ j 1)))
      ((= j n) #f)
      (let ((ai (vector-ref a i))
            (aj (vector-ref a j)))
        ;; use float versions of + and *
        ;; since this is where most of the time is used
        (set! acc (fl+ acc
                       (fl+ (fl* (car ai) (cdr aj))
                            (fl* (cdr ai) (car aj))))))))

  (write acc)
  (newline))
具体实现(锁定)只是为了说明在运行时完成的类型检查确实会产生影响。此代码的运行速度比以前的优化快30%:

#lang racket

;; this imports import the * and + for floats as unsafe-fl* etc. 
(require racket/unsafe/ops)

(let* ((n (* 1024 16))
       (a (make-vector n))
       (acc 0.0)) ; We want float, lets tell Scheme about that!

  (do ((i 0 (+ i 1))
       (f 0.0 (+ f 1)))
    ((= i n) #f)
    ;; using inexact f instead of integer i
    ;; makes every result of cos and sin inexact
    (vector-set! a i (cons (cos f) (sin f))))

  (do ((i 0 (+ i 1)))
    ((= i n) #f)
    (do ((j 0 (+ j 1)))
      ((= j n) #f)
      ;; We guarantee argument is a vector
      ;; and nothing wrong will happen using unsafe accessors
      (let ((ai (unsafe-vector-ref a i))
            (aj (unsafe-vector-ref a j)))
        ;; use unsafe float versions of + and *
        ;; since this is where most of the time is used
        ;; also use unsafe car/cdr as we guarantee the argument is
        ;; a pair.
        (set! acc (unsafe-fl+ acc
                              (unsafe-fl+ (unsafe-fl* (unsafe-car ai) (unsafe-cdr aj))
                                          (unsafe-fl* (unsafe-cdr ai) (unsafe-car aj))))))))

  (write acc)
  (newline))

我努力保持了原始代码的风格。它不是非常惯用的方案。例如,我根本不会使用
set!
,但它不会影响速度。

您是否使用
-O3
g++
?@MaxB Yes.C在
0.25s
中运行,并在
2.5s
中编译方案,而您的原始代码则运行大约
6.5s
(我用
time
平均打了20个电话)你能把你的方案代码粘贴到答案吗?我假设你把所有的算术函数调用都改为非通用版本。当然,@ Max B。最后一个不是方案,但是它也不是最快的改进。C++最简单的类似:但是scheme bytevector。最精确的速度比较是将std::vector与固定大小的整数R6RS字节向量操作进行比较。这几乎肯定会更快,因为它避免了scheme vector中存在的指针间接寻址。
#!r6rs
(import
 (rnrs)
 ;; import the * and + that only work on floats (which are faster, but they still check their arguments)
 (only (rnrs arithmetic flonums) fl+ fl*))


(let* ((n (* 1024 16))
       (a (make-vector n))
       (acc 0.0)) ; We want float, lets tell Scheme about that!

  ;; using inexact f instead of integer i
  ;; makes every result of cos and sin inexact
  (do ((i 0 (+ i 1))
       (f 0.0 (+ f 1)))
    ((= i n) #f)
    (vector-set! a i (cons (cos f) (sin f))))

  (do ((i 0 (+ i 1)))
    ((= i n) #f)
    (do ((j 0 (+ j 1)))
      ((= j n) #f)
      (let ((ai (vector-ref a i))
            (aj (vector-ref a j)))
        ;; use float versions of + and *
        ;; since this is where most of the time is used
        (set! acc (fl+ acc
                       (fl+ (fl* (car ai) (cdr aj))
                            (fl* (cdr ai) (car aj))))))))

  (write acc)
  (newline))
#lang racket

;; this imports import the * and + for floats as unsafe-fl* etc. 
(require racket/unsafe/ops)

(let* ((n (* 1024 16))
       (a (make-vector n))
       (acc 0.0)) ; We want float, lets tell Scheme about that!

  (do ((i 0 (+ i 1))
       (f 0.0 (+ f 1)))
    ((= i n) #f)
    ;; using inexact f instead of integer i
    ;; makes every result of cos and sin inexact
    (vector-set! a i (cons (cos f) (sin f))))

  (do ((i 0 (+ i 1)))
    ((= i n) #f)
    (do ((j 0 (+ j 1)))
      ((= j n) #f)
      ;; We guarantee argument is a vector
      ;; and nothing wrong will happen using unsafe accessors
      (let ((ai (unsafe-vector-ref a i))
            (aj (unsafe-vector-ref a j)))
        ;; use unsafe float versions of + and *
        ;; since this is where most of the time is used
        ;; also use unsafe car/cdr as we guarantee the argument is
        ;; a pair.
        (set! acc (unsafe-fl+ acc
                              (unsafe-fl+ (unsafe-fl* (unsafe-car ai) (unsafe-cdr aj))
                                          (unsafe-fl* (unsafe-cdr ai) (unsafe-car aj))))))))

  (write acc)
  (newline))