如果有人发现截至2019.1.30之前的评论和本文内容对不上,那是因为该日之前演算法有过一次大的更新,以至于本文应该被重写。目前的内容是2019.1.30重写的以及此后在此基础之上进行的非显著修改的结果。此前的版本见如下备份。

astrojhgu/adaptrapezoid_benchmark?

github.com图标

o/o/o/o/o/o/o/o/以o/o/o/o/o/o/o/o/

o/o/o/o/o/o/o/o/下o/o/o/o/o/o/o/o/

o/o/o/o/o/o/o/o/是o/o/o/o/o/o/o/o/

o/o/o/o/o/o/o/o/正o/o/o/o/o/o/o/o/

o/o/o/o/o/o/o/o/文o/o/o/o/o/o/o/o/

动因

通过实际问题,比较若干潜在适合于科学计算的编程语言的运行速度。

比较的原则

确保演算法一致:

尽可能确保在伪代码相同的条件下进行比较,避免演算法的选择对比较结果的影响。例如,本文中所选用的演算法是自适应梯形积分法。在这一前提下,用不同的语言实现这一演算法,并对同一个被积函数,在相同的精度要求下进行问题求解,并比较得到结果所需要的时间。毫无疑问,存在精度收敛速度更快的演算法,例如辛普森方法、高斯积分法等等,但是作者不希望演算法本身的速度差异被引入,因此所有的比较都将确保采用同一种演算法。

伪代码尽可能保持一致:

即使是相同的演算法,在实现过程中,也可以存在不同的伪代码。例如在此前的一个版本中,作者选用了一种保存了过多冗余信息的伪代码。本文尽可能确保所选用的伪代码逻辑结构贴近实用代码,并在不同语言之间保持一致。

例外:

某些语言(Haskell),并不适合采用类C语言中基于迭代的演算法来编写,因此不得不采用基于递归的演算法。

用于比较的问题

问题描述:

求如下定积分

int_0^sqrt{8pi}sin(x^2)dx

为什么选取这个函数( sin(x^2) )作为被积函数?

因为这个函数结构丰富,各阶导数均不全局为0,对积分演算法有一定的要求。

实现伪代码

演算法1(总体演算法)

  1. 设定被积函数F、积分精度 epsilon .
  2. 初始化一系列初始分割点, 初始分割点的x坐标依次递增。这n个分割点对应与n-1个子积分区间。例如对于分割点 x_i,( i=0..n-1) 对应的初始积分区间为 [x_0, x_1], [x_1, x_2], cdots [x_{n-2}, x_{n-1}]
  3. 对于任何积分区间 [a,b] 上的积0分结果,用函数 I{F, a, b} 加以计算, 函数 I 的定义见演算法2。
  4. 将每一个积分区间上的积分结果按照绝对值升序排列,并从前到后求和,得到最终积分结果。

演算法2(对于 I 的定义)

  1. 计算偏差 delta=T{F, a, b}-T{F, a, frac{a+b}{2}}-T{F, frac{a+b}{2}, b} ,其中 T{F, a, b}=frac{b-a}{2}(F(a)+F(b))
  2. 如果 |delta|ltfrac{epsilon}{W}(b-a) , go to 3, 否则 go to ;其中W是原始的积分区间.
  3. 返回  T{F, a, (a+b)/2}+T{F, (a+b)/2,b)
  4. 返回 I{F, a, (a+b)/2)+I{F, (a+b)/2, b)

对于强调函数式编程风格的语言(例如Haskell),将采用递归方式实现,对于强调指令式编程风格,但没有显式尾递归的语言(例如C++、Rust、Python、Julia),将采用模拟递归方式。对于有尾递归的语言(例如Scala),将尽量用尾递归和模拟递归方式实现(取决于我有没有时间)。

代码

本文所涉及的代码见

astrojhgu/adaptrapezoid_benchmark?

github.com
图标

目录

对于各个语言的实现和结果,见下(待续)。


推荐阅读:
相关文章