0
votes

Comment ce code de système renvoie-t-il une valeur?

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*


2 commentaires

Le test si évaluant sur true le rend renvoyer (* 2 e) .


Si vous réécrivez le nommé, laissez une fonction distincte qui n'est pas appelée «boucle», vous pourriez le voir plus claire.


4 Réponses :


4
votes

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?

Non, l'idée est différente: à un moment donné, l'ordinateur est toujours Diviser Diviser par 2, mais le résultat ( E ) devient indiscernable de 0 [updément: Dans le contexte de l'addition de point flottant uniquement - très bon point mentionné dans le commentaire] ( E + 1.0 = 1.0 , c'est exactement ce que si clause vérifie). Nous savons certainement que le précédent E é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 .


2 commentaires

E ne devient pas indiscernable de 0 : (+ 1.0 e) devient indiscerné de 1.0 , 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)) n'implique pas (= E 0)



1
votes

Il devient plus clair lorsque vous vous débarrassez de la notation confuse nommée. XXX

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 boucle était très imprécis et déroutant et la nommée d'epsilon à E est un choix très malheureux. Nommage est la chose la plus importante pour le code lisible.

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

Le nommé Laissez définir et appelle / exécute une fonction / procédure. Éviter cela conduirait à un meilleur code - puisque plus clair.

dans la LISP commune Une telle construction serait beaucoup plus claire exprimée: xxx

dans la mise en œuvre de clis, cette donne: 1.1920929e-7


2 commentaires

* Machine-epsilon * tel que défini dans la question est numéro, et c'est aussi une variable globale.


@TFB OUI, (Définir * Machine-EPSILON * ...) est une définition variable. Ce que je voulais dire, c'était que le (let ...) 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.




1
votes

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, 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.

en particulier (/ * 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>

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


0 commentaires