1

一位朋友在他的代码库中发现了一个二次贝塞尔曲线函数,该函数使用开关表的巨大老鼠巢来执行计算。他要求我找到一个简短的表达式,让他能够替换巨大的代码块。

为了满足两种不同的好奇心,我想我会尝试在 OCaml 中实现该功能。我是一个非常新手的 OCaml 程序员,我也不熟悉这个函数,而且这个具体的实现很难通过谷歌得到。

非常感谢对函数的性能/正确性及其实现的批评。

二次贝塞尔曲线的实现:

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.);;
4

3 回答 3

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)
于 2008-09-28T14:49:45.083 回答
2

我有两个建议:

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

此外,您可以将迭代的分辨率设为可选参数,例如?(epsilon=0.1).

作为一个 ocaml 程序员,除此之外我看不出有什么错误——只要 P1 和 P2 实际上是常量。将其编译下来,看看在将 List.rev 移入或移出尾递归之间有什么区别。

于 2008-09-28T03:32:23.727 回答
1

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

于 2008-09-28T15:20:40.343 回答