这是OCaml中二次Bézier函数的合理实现吗?

时间:2008-09-28 02:42:54

标签: ocaml bezier

一位朋友在他的代码库中遇到了二次Bézier曲线函数,该函数使用了一个巨大的交换表老鼠来执行计算。他挑战我找到一个简短的表达方式,让他能够取代庞大的代码块。

为了满足两种不同的好奇心,我想我会尝试在OCaml中实现这个功能。我是一个非常新手的OCaml程序员,我也不熟悉这个功能,这个特定的实现很难通过谷歌来实现。

对功能的性能/正确性及其实现的批评非常受欢迎。

Quadratic Bézier Curve的实施:

let rec b2 n =
let p1 = -10. in
let p2 = 10. in
let q = n*.n in
let rec b2i n i hd =
  if i > n then
    List.rev hd
  else
    let t = i /. n in
  b2i n (i+.1.) ((((1.-.t)**2.)*.p1+.(2.*.t*.(1.-.t)*.q)+.(t**2.)*.p2) :: hd)
in b2i n 0. []
;;
let floatprint lst = List.iter (fun f -> Printf.printf "%f; " f) lst ;;
floatprint (b2 8.);;

3 个答案:

答案 0 :(得分:3)

b2不是递归的,所以不需要[let rec b2 n =]。因为n永远不会改变,所以不需要将它作为b2i的参数,只需使用封闭范围中的n即可。你的内部函数应该依赖于p0,p1和p2,但我看它取决于-10。,n ** 2和10.该函数也有[0.0; 1.0; 2.0; ...; n.0]到最终值。你能写下来吗?

let b i = 
  let t = i /. n in
  let tminus = (1.-.t) in
  (tminus *. tminus *. p0) +. (2. *. t *. tminus *. p1) +. (t *. t * p2)
in
List.map b ([generate list 1.0; 2.0; ... n.0])

生成列表1.0 ... n.0的函数可以是:(对于小n)

let rec count m n = if m > n then [] else m :: (count (m+.1.) n)

答案 1 :(得分:2)

我有两点建议:

您应该在List.rev返回后调用b2i,以便ocaml可以利用它的尾递归优化。我不确定ocaml将如何处理当前的实现,List.rev是尾递归的。您会注意到在this post中,它就是这样完成的。

此外,您可以使迭代的分辨率成为?(epsilon=0.1)之类的可选参数。

作为一名ocaml程序员,我不会在这里看到太多错误 - 只要P1和P2实际上是常量。编译它,看看程序集在将尾部递归内部或外部移动List.rev之间的区别。

答案 2 :(得分:1)

这可能是picayune,但hd不是列表参数的好名称。 List.hd是一个返回列表第一个元素的标准函数。使用hd作为列表的名称将导致混淆。