2008-09-28 7 views
1

Un ami est tombé sur une fonction de courbe de Bézier quadratique dans sa base de code qui utilisait un nid de rats gigantesque d'une table de commutation pour effectuer le calcul. Il m'a mis au défi de trouver une seule expression courte qui lui permettrait de remplacer le gigantesque bloc de code. En essayant de satisfaire deux curiosités différentes, j'ai pensé que j'essaierais d'implémenter la fonction dans OCaml. Je suis un programmeur OCaml très novice et je suis également peu familier avec la fonction et cette implémentation spécifique est difficile à trouver via Google.Est-ce une implémentation raisonnable de la fonction de Bézier quadratique dans OCaml?

Les critiques sur la performance/l'exactitude de la fonction ainsi que sur sa mise en œuvre sont très appréciées.

Mise en œuvre de 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.);; 

Répondre

3

b2 n'est pas récursif, donc pas besoin de [let rec b2 n =]. Puisque n ne change jamais, pas besoin de l'avoir comme argument pour b2i, il suffit d'utiliser n depuis la portée englobante. Votre fonction interne devrait dépendre de p0, p1 et p2, mais je le vois en fonction de -10., N ** 2 et 10. La fonction a également la forme d'une carte de [0.0; 1,0; 2,0; ...; n.0] aux valeurs finales. Pourriez-vous écrire:

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]) 

Une fonction pour générer la liste 1.0 ... n.0 pourrait être: (pour les petites n)

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

J'ai deux suggestions:

Vous devez appeler List.rev après b2i retours afin OCaml peut l'exploiter est l'optimisation de la queue-récursion. Je ne suis pas sûr à quel point ocaml traitera de la mise en œuvre actuelle, List.rev est récursif à la queue cependant. Vous remarquerez que dans this post c'est fait comme ça.

De même, vous pouvez faire de la résolution de l'itération un argument optionnel comme ?(epsilon=0.1).

En tant que programmeur ocaml, je ne vois pas grand chose de mal ici à part ça - tant que P1 et P2 sont en fait des constantes. Compilez-le et voyez quelle est la différence d'assemblage entre le déplacement de List.rev à l'intérieur ou à l'extérieur de la récursion de queue.

+0

Le chemin de code list.rev n'affecte pas la récursivité de queue de b2i. Bonne idée sur epsilon. Probablement p1 et p2 devraient aussi devenir des arguments. – Thelema

1

Cela peut être Picayune, mais hd est pas bon nom pour un paramètre de liste. List.hd est une fonction standard qui renvoie le premier élément d'une liste. En utilisant hd comme nom pour une liste mènera à la confusion.

+0

quel identifiant utilisez-vous pour ce type d'argument/liste? – Thelema

+0

J'utilise des noms comme xs, ys et zs pour les listes, et x, y, z pour les éléments de ces listes. Ne pas dire que c'est le meilleur moyen. –

+0

puisque c'est un accumulateur, j'aime utiliser acc – nlucaroni

Questions connexes