Ce code est tiré de la structure et de l'interprétation de Sussman and Wisdom de la mécanique classique em>, son objectif est de dériver (près de) le plus petit point flottant positif que la machine hôte prend en charge. https://github.com/hnarayanan/sicm/ blob / e37f011db68f8fc51ae309cd61bf497b90970da / scputils / src / noyau / numeric.scm
exécuté dans le drracket Résultats 2.220446049250313e-016 sur ma machine. P>
Ma question, qu'est-ce que cela revient même une valeur? Ce code est de la queue récursive et il est logique à un moment donné que l'ordinateur ne peut plus diviser par 2. Pourquoi ne jetez-t-il pas? P>
(define *machine-epsilon* (let loop ((e 1.0)) (if (= 1.0 (+ e 1.0)) (* 2 e) (loop (/ e 2))))) *machine-epsilon*
4 Réponses :
Ce code est à la queue récursive, et il est logique à un moment donné que l'ordinateur ne peut plus diviser par 2. Pourquoi ne jette pas? P> blockQuote>
Non, l'idée est différente: à un moment donné, l'ordinateur est toujours Diviser em> Diviser par 2, mais le résultat (
E code>) devient indiscernable de 0 [updément: Dans le contexte de l'addition de point flottant uniquement em> - très bon point mentionné dans le commentaire] (
E + 1.0 = 1.0 code>, c'est exactement ce que
si code> clause vérifie). Nous savons certainement que le précédent
E code> était toujours supérieur à zéro "du point de vue de la machine" (sinon, nous n'aurions pas le point d'exécution actuel), donc nous renvoyons simplement
e * 2 code>. P>
E code> ne devient pas indiscernable de
0 code>:
(+ 1.0 e) code> devient indiscerné de
1.0 code>, qui est un très chose différente.
@TFB La question n'était pas "pourquoi si la clause fonctionne", n'est-ce pas? :) Mais sérieusement, vous êtes absolument correct - (= 1.0 (+ e 1.0)) code> n'implique pas
(= E 0) code>
Il devient plus clair lorsque vous vous débarrassez de la notation confuse nommée. est ce que le code fait réellement.
Alors maintenant, nous voyons pour ce que le nommé Let expression est bon.
Il définit localement la fonction et l'exécute localement. Juste que le nom de la fonction que Donc, cet exemple de SICP devrait être un exemple de mauvais choix de dénomination. (D'accord, peut-être qu'ils l'ont fait par intention de former les étudiants). P> Le nommé Laissez définir et appelle / exécute une fonction / procédure. Éviter cela conduirait à un meilleur code - puisque plus clair. P> dans la LISP commune Une telle construction serait beaucoup plus claire exprimée: p> dans la mise en œuvre de clis, cette donne: boucle code> était très imprécis et déroutant et la nommée d'epsilon à
E code> est un choix très malheureux. Nommage est la chose la plus importante pour le code lisible. P>
1.1920929e-7 code> p> p>
* Machine-epsilon * code> tel que défini dans la question est i> numéro, et c'est aussi une variable globale.
@TFB OUI, (Définir * Machine-EPSILON * ...) code> est une définition variable. Ce que je voulais dire, c'était que le
(let ...) code> construit est obscurcissant deux choses: une définition de la fonction et son appel. Mais vrai, au début quand j'ai écrit, j'étais confus. - D'accord j'ai supprimé une grande partie.
Ce Formulaire de liant < / a> est le sucre syntaxique pour la récursion. p>
Vous pouvez éviter d'utiliser trop de syntaxe jusqu'à ce que vous maîtrisiez la langue et écrivez autant que possible en utilisant la langue du noyau, pour vous concentrer sur le problème essentiel. Par exemple, dans le texte intégral du SICP, jamais spécifié ce sucre syntaxique pour l'itération. P>
La définition R6RS pour l'itération est ici . P>
Le but de ce code est pas em> pour trouver le plus petit flotteur que la machine peut supporter: il est de trouver le plus petit flotteur, en particulier Je ne suis pas assez familier avec des normes de point flottant , mais le nombre que vous envisagez probablement est ce que les appels LISP communs epsilon code> tel que
( = (+ 1.0 epsilon) 1.0) code> est faux. Ce numéro est utile car c'est la limite supérieure de l'erreur que vous obtenez d'ajouter en particulier ce que vous savez est que, disons,
(+ xy) code> est dans la plage [(x + y) * ( 1 - epsilon), (x + y) * (1 + epsilon)], où dans la seconde expression
+ code> & C signifie les opérations idéales sur les nombres.
(/ * Machine-epsilon * 2) code> est un nombre parfaitement fine, tel quel
(/ * machine-epsilon * 10000) code> par exemple et
(* (/ * (/ * Machine-epsilon * x) x) code> sera très proche de
* machine-epsilon * code> pour de nombreuses valeurs raisonnables de
x code>. C'est juste le cas que
(= (+ (/ * machine-epsilon * 2) 1.0) 1.0) code> est vrai. P>
le moins positif-float code> (ou ses variantes). Dans la raquette, vous pouvez obtenir une certaine approximation à celle-ci par P>
(define *least-positive-mumble-float*
;; I don't know what float types Racket has if it even has more than one.
(let loop ([t 1.0])
(if (= (/ t 2) 0.0)
t
(loop (/ t 2)))))
Le test
si code> évaluant sur true le rend renvoyer
(* 2 e) code>.
Si vous réécrivez le nommé, laissez une fonction distincte qui n'est pas appelée «boucle», vous pourriez le voir plus claire.