J'essaie d'implémenter la méthode Newton-Raphson sur Haskell, et jusqu'à présent, j'ai réussi à la faire fonctionner en utilisant la fonction itérer
, mais le problème est qu'elle renvoie une liste infinie en raison de la nature de la fonction d'itération, je cherche donc à trouver un moyen d'arrêter la boucle lorsque la valeur obtenue dans une itération tombe dans une marge d'erreur définie, et de renvoyer ladite valeur
J'ai regardé quelques articles de blog et même quelques questions ici, mais je suis assez nouveau dans haskell et je ne connais pas complètement la syntaxe, donc pour moi, lire des exemples de code ou de la documentation est vraiment difficile à présent.
Définitions de f (x) et g (x) (les dérivés) ne sont pas pertinents:
newton x0 = iterate step x0 where step xn = xn - ((f xn)/(g xn))
Je travaille actuellement en prenant les premiers éléments de la liste donnée, en utilisant take 4 $ newton 3.5 dans l'invite GHCi, mais la liste retournée par
iterate
est infinie, donc je ne peux pas utiliser de fonction de queue dessus.
Mon idée est de définir une constante quelque part, margin = 0,0001
ou quelque chose comme e à, et lorsque la dernière itération de la fonction newton tombe derrière la marge, la fonction itérer
s'arrête, et j'ai le résultat final
3 Réponses :
Vous souhaitez tester des paires de valeurs consécutives générées par newton
. Cela signifie que dropWhile
du Prelude ne suffira pas, car il ne teste que des éléments individuels. À la place, vous pouvez utiliser quelque chose comme ceci dropWhileList
de MissingH:
newton :: Double -> Double newton x0 = dropWhileList (not . goal) (iterate step x0) !! 1 where step xn = xn - ((f xn)/(g xn)) goal (xa:xb:_) = abs (xb - xa) < margin goal _ = False
!! 1
vous donne le deuxième élément de la liste. Bien qu'il s'agisse d'une fonction partielle (elle échoue si la liste n'a pas de deuxième élément), elle est ici sûre à utiliser (comme iterate
génère une liste infinie, vous aurez un résultat tant que la méthode de Newton converge).
Une variante de la réponse de duplode qui n'utilise que des fonctions standard:
newton :: Double -> Double newton x0 = (snd . head . dropWhile (not . goal)) (zip approxs (tail approxs)) where approxs = iterate step x0 step xn = xn - (f xn / g xn) goal (xa, xb) = abs (xb - xa) < margin
Pour déterminer si notre objectif a été atteint, nous devons examiner les paires adjacentes d'éléments de la liste infinie produite par itérer
. Pour ce faire, nous utilisons l'astuce standard consistant à compresser la liste avec sa propre queue. (Si vous vous sentez plus effronté, pensez à utiliser (zip tail) approxs
au lieu de zip approxs (tail approxs)
. De cette façon, vous n'êtes pas obligé de le faire. mentionner approxs
deux fois dans l'expression, ce qui est certes un peu inutile.)
Cela nous donne une liste infinie de paires, à partir de laquelle nous supprimons des éléments jusqu'à la différence entre les composants d'un la paire devient assez petite. À ce stade, nous extrayons la tête de la liste restante (une paire) et prenons le deuxième composant.
Je dirais que cette réponse est une nette amélioration: si "vous voulez tester des paires de valeurs consécutives", il vaut mieux tester littéralement paires de valeurs :)
Reprenant la suggestion de oisdk d'utiliser jusqu'à
...
newton :: Double -> Double newton = snd . until goal (move . snd) . move where step xn = xn - (f xn)/(g xn) move xn = (xn, step xn) -- The cheeky spelling is (,) <*> step goal (xa,xb) = abs (xb - xa) < margin
... pour une implémentation qui ne génère pas littéralement de liste:
until :: (a -> Bool) -> (a -> a) -> a -> a
Cela vaut la peine de comparer cela avec l'implémentation basée sur le zip
de melpomene et en notant les parallèles.
Peut-être voulez-vous envisager
takeWhile
." la liste retournée par
iterate
est infinie, donc je ne peux pas utiliser une fonction de queue dessus. " Pourquoi pas?tail
fonctionne très bien sur des listes infinies.Note tangentielle: si vous souhaitez utiliser
comme arguments.
newton
avec différentes fonctions et marges, il peut être utile de passer la margef
,g
etQue diriez-vous de la fonction
jusqu'à
?