我是博士生.在我的论文的介绍中,我对线性代数工具的表现力和表现之间的妥协深感兴趣.
举个简单的例子,我使用向量表达式的范数计算.我的例子的C代码是:
float normExpression3(float a, float *W, float b, float *X, float c, float*Y){
double norm = 0;
for (int i=0; i<n; ++i) // n in [3e6; 2e8]
{
float tmp = a*W[i]+b*X[i]+c*Y[i];
norm+=tmp*tmp;
}
return sqrtf(norm);
Run Code Online (Sandbox Code Playgroud)
}
我比较了用不同技术实现的性能.由于矢量很大(几百万个元素),性能受到存储器带宽的限制.但是,不同方法之间存在巨大差异.
我编写的优化C版本不具有表现力(一个新函数必须写为第四个向量)并且非常难看(线程化和向量化)但实现了6.4 GFlops.另一方面,MATLAB代码非常好:
result = norm(a*W+b*X+c*Y)
Run Code Online (Sandbox Code Playgroud)
但只能达到0.28 GFlops.
C++模板表达式点菜闪电++提供既表达性和表演给用户(6.5 GFLOPS).
作为我的分析的一部分,我想知道功能语言如何与这些方法进行比较.我想在Haskell或OCaml中展示一个例子(AFAIK,两者都很适合这种操作).
我不知道这些语言.我可以了解他们提供我的例子,但这不是一个公平的比较:我不确定是否能够提供一个允许表现力和表现的实现.
所以我的两个问题是:1)哪种语言最适合?2)如何在不影响实现的一般性的情况下有效地计算向量表达式的范数?
提前,谢谢!
威尔弗里德K.
编辑:纠正的类型norm
累加器float
到double
小智 5
值得一提的是,以下是您的函数的OCaml版本:
let normExpression3 a w b x c y =
let n = Array.length w in
if not (n = Array.length x && n = Array.length y)
then invalid_arg "normExpression3";
let (@) = (Array.unsafe_get : float array -> int -> float) in
let rec accum a w b x c y n i norm =
if i = n then sqrt norm else
let t = a *. (w @ i) +. b *. (x @ i) +. c *. (y @ i) in
accum a w b x c y n (i + 1) (norm +. t)
in accum a w b x c y n 0 0.
Run Code Online (Sandbox Code Playgroud)
它为性能提供了一些补贴,即:
应该针对封闭的内循环检查最后的优化,因为如此多的参数寄存器溢出可能超过引用封闭参数的成本.
请注意,通常不会对这种优化感到烦恼,除非有人在benchark中竞争;-)
注意,您还需要使用64位OCaml进行测试,因为数组限制为4兆元素.