这是 OCaml 中二次 Bézier 函数的合理实现吗?
一位朋友在他的代码库中发现了一个二次贝塞尔曲线函数,该函数使用开关表的巨大老鼠巢来执行计算。 他要求我找到一个简短的表达式来替换巨大的代码块。
为了满足两种不同的好奇心,我想尝试在 OCaml 中实现该函数。 我是一个非常新手的 OCaml 程序员,我也不熟悉这个函数,而且这个特定的实现很难通过 Google 获得。
非常感谢对该函数的性能/正确性及其实现的批评。
二次贝塞尔曲线的实现:
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.);;
A friend came across a quadratic Bézier curve function in his codebase that used a gigantic rats nest of a switch table to perform the computation. He challenged me to find a single, short expression that would allow him to replace the gigantic block of code.
In attempting to satisfy two different curiosities, I thought I'd try implementing the function in OCaml. I'm a very novice OCaml programmer and I'm also unfamiliar with the function and this specific implementation is hard to come by via Google.
Critiques on both the function's performance/correctness as well as its implementation are very much appreciated.
Implementation of 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.);;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
b2 不是递归的,因此不需要 [let rec b2 n =]。 由于 n 永远不会改变,因此无需将其作为 b2i 的参数,只需使用封闭范围中的 n 即可。 你的内部函数应该依赖于 p0、p1 和 p2,但我认为它依赖于 -10.、n**2 和 10。该函数还具有来自 [ 0.0; 的映射的形式。 1.0; 2.0; ...; n.0] 到最终值。 你能写一下吗:
生成列表 1.0...n.0 的函数可以是:(对于小 n)
b2 isn't recursive, so no need for [let rec b2 n =]. Since n never changes, no need to have it as argument to b2i, just use n from the enclosing scope. Your inner function should depend on p0, p1 and p2, but I see it depending on -10., n**2 and 10. The function also has the form of a map from [ 0.0; 1.0; 2.0; ...; n.0] to the final values. Could you write it:
A function to generate the list 1.0...n.0 could be: (for small n)
我有两个建议:
您应该在
b2i
返回后调用List.rev
,以便 ocaml 可以利用它的尾递归优化。 我不确定 OCaml 处理当前实现的效果如何,尽管List.rev
是尾递归的。 您会注意到这篇文章中的做法如下那。另外,您可以将迭代的分辨率设置为可选参数,例如
?(epsilon=0.1)
。作为一名 ocaml 程序员,除此之外我没有看到太多错误——只要 P1 和 P2 实际上是常量。 编译它,看看将 List.rev 移入或移出尾递归在汇编中有何不同。
I have two suggestions:
You should call
List.rev
afterb2i
returns so ocaml can exploit it's tail-recursion optimizations. I am not sure how well OCaml will deal with the current implementation,List.rev
is tail-recursive though. You'll notice that in this post it is done like that.Also, you can make the resolution of the iteration be an optional argument like
?(epsilon=0.1)
.As an ocaml programmer I don't see much wrong here aside from that --as long as P1 and P2 are in fact constants. Compile it down and see what the difference in assembly is between moving List.rev inside or out of the tail-recursion.