【发布时间】:2021-01-13 04:34:13
【问题描述】:
为了加强我(薄弱的)函数式编程技能,我正在研究 Piegl 和 Tiller 将所有算法转换为 Haskell 的 NURBS 书 .这是一个非常好的和有启发性的过程,但我被算法 2.2 卡住了,这里是伪代码(一个类似 C 的 reworked-by-me 版本):
double[] BasisFuns( int i, double u, int p, double U[]) {
double N[p+1];
double left[p+1];
double ritght[p+1];
N[0]=1.0;
for (j=1; j<=p; j++) {
left[j] = u - U[i+1-j];
right[j] = U[i+j] - u;
double saved = 0.0;
for (r=O; r<j; r++) {
double temp= N[r]/(right[r+1]+left[j-r]);
N[r] = saved+right[r+1]*temp;
saved = left[j-r]*temp;
}
N[j] = saved;
}
return N;
}
外层循环看起来很简单,但内层循环对N 的元素进行了所有这些必要的有序修改,这让我很头疼。
我开始这样设置:
baseFunc :: RealFrac a => Int -> Int -> a -> [a] -> [a]
baseFunc i p u knots
[ ??? | j <- [1..p], r <- [0..j] ]
where
left = [ u - knots !! (i+1-j) | j <- [ 1 .. p ]
right= [ knots !! (i+j) - u | j <- [ 1 .. p ]
但我觉得我可能完全偏离了道路。
我已经基于 Eq. 2.5,因此在这里我希望保持命令式版本的性能。
【问题讨论】:
-
我不确定这是否可以很好地翻译。它利用了对数组的大量随机访问,并且到处都有突变。特别是在性能是一个问题的情况下,我会将其转换为 Haskell,保持其命令性并使用
STUArray和STmonad。 -
直接从 C 翻译可能不是保持性能的方式。编译器做的比你想象的要多。
-
@chepner 这本书还提供了递归方程(方程 2.5)。我不确定它们是否适合这个场地。无论如何,从他们开始,在 Haskell 中获得一个有效的实现真的很容易,但是获得与上面的伪代码一样高效的东西似乎...... hard
-
诚然,在您拥有两个工作实现之前,您无法真正进行基准测试,但我怀疑您低估了编译器可以使用递归定义执行的功能。我怀疑即使是优化的 C 编译器也会产生与你所期望的 C 代码完全不同的东西。
标签: list algorithm haskell functional-programming