一位朋友在他的代码库中遇到了二次Bézier曲线函数,该函数使用了一个巨大的交换表老鼠来执行计算。他挑战我找到一个简短的表达方式,让他能够取代庞大的代码块。
为了满足两种不同的好奇心,我想我会尝试在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.);;
答案 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
作为列表的名称将导致混淆。