2008-09-28 3 views
1

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

При попытке удовлетворить два разных любопытства, я подумал, что попробую реализовать функцию в OCaml. Я очень новичок программист OCaml, и я также не знаком с этой функцией, и эта специфическая реализация трудно найти через Google.

Очень ценятся как характеристики, так и правильность функционирования, а также его реализация.

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

ответ

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 может быть: (для малого п)

let rec count m n = if m > n then [] else m :: (count (m+.1.) n) 
2

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

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

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

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

+0

list.rev codepath не повлияет на рекурсию хвоста b2i. Хорошая идея на эпсилон. Вероятно, p1 и p2 тоже должны стать аргументами. – Thelema

1

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

+0

какой идентификатор вы используете для такого рода аргументов/списка? – Thelema

+0

Я использую имена, такие как xs, ys и zs для списков, и x, y, z для элементов этих списков. Не сказать, что это лучший способ. –

+0

, так как это аккумулятор, мне нравится использовать acc – nlucaroni