Aller au contenu

Une fonction qui \"apprend\"


(gile)

Messages recommandés

Salut,

 

Pour évaluer si un entier strictement positif est un nombre premier, il faut évaluer s'il est multiple ou non de tous les nombres premiers (sauf 1) qui lui sont inférieurs.

Si tous ces nombres premiers ne sont pas connus, il faut les rechercher de la même manière.

Pour éviter de refaire ces évaluations à chaque fois, il est intéressant de garder en mémoire les nombres premiers précédemment calculés.

 

La fonction LISP defun-q définit une fonction sous forme de liste (au lieu de génèrer une fonction compilée comme defun), ceci permet de redéfinir la fonction à l'intérieur même de sa définition.

On peut donc construire une fonction qui va "acquérir des connaissances" lors de son exécution et les conserver en son sein.

 

Dans l'exemple ci dessous, la fonction premier ne "connaît" au départ que 2 et 3 comme nombres premiers (je suis allé jusqu'à 3 pour pouvoir incrémenter la recherche de nouveaux nombres premiers de 2 au lieu de 1). À chaque fois qu'elle va rechercher et trouver de nouveaux nombres premiers, elle va les "apprendre" et pourra les réutiliser au prochain appel.

 

Pour tester lancer TEST à la ligne commande et entrer un entier.

 

(defun-q
 premier
 (nombre / liste diviseur boucle result)
 (setq liste '(2 3)) ;_ liste initiale
 (if (and (= (type nombre) 'INT) (< 0 nombre))
   
   ;; si le nombre est un nombre premier connu
   (if (or (member nombre liste) (= 1 nombre))
     
     ;; alors, résultat :
     (alert (strcat "Je connais : " (itoa nombre) " est un nombre premier."))
     
     ;; sinon, s'il est inférieur au plus grand nombre premier connu
     (if (< nombre (setq diviseur (last liste)))
       
       ;; alors, résultat :
       (alert (strcat "Je connais : " (itoa nombre) " n'est pas un nombre premier."))
       
       ;; sinon, s'il est multiple d'un nombre premier connu
       (if (vl-some '(lambda (x) (multiple nombre x)) liste)
         ;; alors, résultat :
         (alert (strcat "J'ai calculé : " (itoa nombre) " n'est pas un nombre premier."))

         ;; sinon, on on évalue tour à tour des diviseurs incrémentés de 2
         ;; à partir du plus grand nombre premier connu
         (progn
           (setq boucle   T
                 diviseur (+ diviseur 2)
           )
           (while (and boucle (<= diviseur nombre))

             ;; si le diviseur est un multiple d'un nombre premier connu
             (if (vl-some '(lambda (x) (multiple diviseur x)) liste)

                ;; alors, incrémentation du diviseur
                (setq diviseur (+ diviseur 2))

                ;; sinon, c'est un nombre premier
                (progn

                  ;; il est ajouté à la liste
                  (setq liste (append liste (list diviseur)))
                  (alert (strcat "J'ai appris un nouveau nombre premier : "
                                 (itoa diviseur)
                         )
                  )

                  ;; si le nombre est un multiple du diviseur
                  (if (multiple nombre diviseur)

                    ;; alors, fin de la boucle
                    ;; si le nombre est égal au diviseur
                    (if (= nombre diviseur)

                      ;; alors, résultat :
                      (alert (strcat "Maintenant, je connais : "
                                     (itoa nombre)
                                     " est un nombre premier."
                             )
                      )

                      ;; sinon, résultat :
                      (progn
                        (alert (strcat "J'ai calculé : "
                                       (itoa nombre)
                                       " n'est pas un nombre premier."
                               )
                        )
                        (setq boucle nil)
                      )
                    )

                    ;; sinon, incrémentation du diviseur
                    (setq diviseur (+ diviseur 2))
                  )
                )
             )
           )
         )
       )
     )
   )
   (alert "Nécessite un entier strictement positif")
 )

 ;; redéfinition de la fonction
 (setq premier
        (cons (car premier)
              (cons (list 'setq 'liste (list 'quote liste))
                    (cddr premier)
              )
        )
 )
 (princ)
)

;; multiple
;; évalue si a est multiple de b, retourne T ou nil

(defun mult (a B) (zerop (rem a B)))

;; commande TEST

(defun c:test (/ nb)
 (initget 7)
 (setq nb (getint "\nEntrez un entier: "))
 (premier nb)
 (princ)
)

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Invité Patrick

defun-q semble avoir fait son apparition dans la version 2000. Pouvoir redéfinir une fonction parce qu'elle est une liste est intéressant dans l'exemple que tu donnes, mais quel serait l'inconvénient de n'utiliser que defun-q plutôt que defun, autrement dit, qu'apporte defun que n'a pas defun-q ?

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

D'après ce que j'ai compris defun-q arrive, comme tu dis, avec Visual LISP pour assurer la compatibilité avec les version antérieures.

Dans ces versions, defun était implémenté pour définir une fonction comme une liste, depuis la définition de fonction est compilée lors de son chargement, ce qui a pour effet d'accélérer son exécution (surtout dans les fonctions récursives).

Aujourd'hui, à part pour ces histoires de compatibilité, defun-q n'est utilisée que quand on a besoin de définir une fonction comme une liste, principalement pour la fonction S::STARTUP, ce qui permet de lui ajouter facilement des fonctions avec append.

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité