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

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

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

实施二次Bé zier曲线

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.);;
有帮助吗?

解决方案

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)

其他提示

我有两点建议:

b2i 返回后应该调用 List.rev ,这样ocaml就可以利用它的尾递归优化。我不确定ocaml将如何处理当前的实现, List.rev 虽然是尾递归的。您会注意到,在这篇文章中,它就像这一点。

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top