Является ли это разумной реализацией квадратичной функции Безье в OCaml? - PullRequest
1 голос
/ 28 сентября 2008

Один знакомый наткнулся на квадратичную функцию кривой Безье в своей кодовой базе, которая использовала гигантское гнездо крыс таблицы переключателей для выполнения вычислений. Он предложил мне найти одно короткое выражение, которое позволило бы ему заменить гигантский блок кода.

Пытаясь удовлетворить два разных любопытства, я решил попробовать реализовать эту функцию в 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.);;

Ответы [ 3 ]

3 голосов
/ 28 сентября 2008

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)
2 голосов
/ 28 сентября 2008

У меня есть два предложения:

Вы должны позвонить List.rev после возврата b2i, чтобы ocaml мог использовать свои оптимизации хвостовой рекурсии. Я не уверен, насколько хорошо ocaml справится с текущей реализацией, хотя List.rev является хвост-рекурсивным. Вы заметите, что в этом посте это сделано так.

Кроме того, вы можете сделать разрешение итерации необязательным аргументом, подобным ?(epsilon=0.1).

Как программист ocaml, я не вижу здесь ничего плохого, если только P1 и P2 фактически являются константами. Скомпилируйте его и посмотрите, какая разница в сборке между перемещением List.rev внутри или из хвостовой рекурсии.

1 голос
/ 28 сентября 2008

Это может быть picayune, но hd не подходит для параметра списка. List.hd - это стандартная функция, которая возвращает первый элемент списка. Использование hd в качестве имени для списка приведет к путанице.

...