Aller au contenu

Exceptions et anomalies dans certaines fonctions Lisp


VDH-Bruno

Messages recommandés

Bonjour,

 

Pour faire suite à une discussion récente sur le forum, vla-get-textstring -> Ne donne pas forcement la bonne valeur, consultable ici

 

Je propose de créer ici un fil de discussion pour répertorier les limitations ou exception (plus ou moins connus et non documenté) de certaines fonctions lisp.

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Fonctions de comparaison <, >, >=, <=, /=, =

 

Pour inaugurer le fil je me lance avec les fonctions <, >, >=, <=, /=, =. Bien que ces fonctions comparent en théorie exclusivement des arguments de type nombre (integer, real) ou string. Elles sont également capables d'évaluer les expressions symboliques T et nil… Ex :

(< nil T) retourne T
(>= nil T) retourne nil

 

Avec toutefois quelques exception à connaitre si on prend l'hypothèse que les fonctions comparent des valeurs booléens, la fonction /= retourne toujours nil et la comparaison de 2 le symbole T n'est pas possible.. Ex:

(< T T) retourne ; erreur: type d'argument de comparaison incorrect: T T

 

Une autre particularité un peu plus intéressante est cette fois de permettre l'évaluation d'arguments nombre ou string avec nil.

(< nil -1 0 1) retourne T 
(< nil "a" "b" "c") retourne T

C'est de cette propriété que je me suis inspiré ici pour écrire un code plus concis.

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Les fonctions "usuel" à arguments indéterminés du type (function [arg ...])

J'avais déjà signalé ici concernant les fonctions + et limité à 255 arguments, ceci est également valable pour l'ensemble des fonctions "usuel" (ex: +, -, max, min, append..).

Ces fonctions retournent aux 256ème arguments le message d'erreur ;erreur: limite interne: nombre d'arguments trop important dans l'appel de la fonction: function

 

Exemple:

$ (eval (cons 'strcat (repeat 255 (setq L255str (cons "a" L255str)))))
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$ (eval (cons 'strcat (repeat 256 (setq L256str (cons "a" L256str)))))
; erreur: limite interne: nombre d'arguments trop important dans l'appel de la fonction: STRCAT
_$

 

 

Evidemment cette limitation ne s'applique pas aux fonctions qualifié de forme spécial <special form> que sont les fonctions structurante du langage comme defun, progn etc..

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Fonction vl-sort

 

Beaucoup savent déjà que la fonction vl-sort supprime les doublons avec les nombres entier

_$ (vl-sort '(1 3.1 5 6.1 5 6.1 1) '<)
(1 3.1 5 6.1 6.1)

Une rapide conversion des listes de nombres en réels contourne le soucis:

_$ (vl-sort (mapcar 'float '(1 3.1 5 6.1 5 6.1 1)) '<)
(1.0 1.0 3.1 5.0 5.0 6.1 6.1)

 

Peut être que beaucoup moins savent qu'il en vat de même avec des valeurs T et nil puissent qu'elles sont également supporté dans les comparaisons (cf post précédent)

_$ (vl-sort '(nil T nil T nil) '>)
(T nil)

 

A noter que T seul est cette fois supporté :blink:

_$ (vl-sort '(T T T) '>)
(T)

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Trigonométrie

 

Le cosinus de 90° (ou 270°) est égal à 0.0, or

(cos (* pi 0.5)) retourne 6.12323e-017

(cos (* pi 1.5)) retourne -1.83697e-016

 

On peut penser que ceci est une imprécision due au codage des nombres réels (double précision en virgule flottante), toujours est-il que ceci peut permettre de définir une fonction tangente (sinus divisé par cosinus) sans se soucier de la division par 0 que devrait provoquer tangente 90° (ou 270°).

 

(defun tan (a) (/ (sin a) (cos a)))

(tan (* pi 0.5)) retourne 1.63312e+016 qui n'est, certes pas égal à l'infini (le résultat mathématique), mais tout de même un très grand nombre (dizaine de millions de milliards) qui renvoie un résultat cohérent avec la fonction inverse :

(= (atan (tan (* pi 0.5))) (* pi 0.5))

retourne T.

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

Lien vers le commentaire
Partager sur d’autres sites

Trigonométrie (suite)

 

La fonction atan accepte 1 ou 2 arguments et ne retourne pas le même résultat pour les angles supérieurs à 90° et inférieurs à 270° (autrement dit, les angles au cosinus négatif) suivant qu'on lui passe 1 ou 2 arguments.

Par exemple, la tangente de 120° est égale à la tangente de 300° :

(setq a1 (/ (* pi 2) 3)		; soit 120°
     t1 (/ (sin a1) (cos a1))  ; soit -1.73205
     a2 (/ (* pi 5) 3)	        ; soit 300°
     t2 (/ (sin a2) (cos a2))  ; soit -1.73205
)

Si on ne passe qu'un argument à atan (t1 ou t2) on obtient logiquement toujours le même résultat : -1.0472, qui correspond à -60° autrement dit 300° (valeur de a2).

Autrement dit, quand on ne passe qu'un argument à atan, l'angle retourné est toujours compris entre 270° et 90° (secteur des cosinus positifs).

 

Pour avoir l'angle retourné sur 360°, il faut appeler atan avec deux arguments (le sinus et le cosinus de l'angle) plutôt qu'avec le résultat de la division des deux termes.

(atan (sin a1) (cos a1))  ; retourne 2.0944 soit 120°
(atan (sin a2) (cos a2))  ; retourne -1.0472 soit -60°

 

La subtilité vient du fait que le sinus de 120° est positif (0.866) alors que celui de 300° est négatif(-0.866) et que cosinus de 120° est négatif (-0.5) alors que celui de 300° est positif (0.5). Dans les deux cas la tangente (division du sinus par le cosinus) renvoie le même résultat, mais pas exactement pour les mêmes raisons.

Un unique argument ne permet pas à atan de connaitre les signes du sinus et du cosinus de l'angle, deux arguments permettent à la fonction de situer l'angle :

- premier quadrant si les deux arguments sont positifs

- second quadrant si le premier (sinus) est positif et le second (cosinus) négatif

- troisième quadrant si les deux sont négatifs

- quatrième quadrant si le premier est négatif et le second positif.

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

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

 

Bonne idée de regrouper les pièges et les subtilités à seul endroit.

 

A ce propos un grand classique : je pense au comportement de la fonction (/ nb1 nb2) qui peut paraitre curieux. Elle permet de diviser, on s'en doute, nb1 par nb2. Compte tenu que nb1 et nb2 peuvent être entiers ou réels, il arrive de se faire piéger quand nb1 et nb2 sont entiers.

 

(/ 5 2) renvoie 2 et non 2.5, comme on aurait pu s'y attendre. Comme 5 et 2 sont des entiers, lisp fait une division entière. Pour avoir une valeur réelle, il faut qu'un des 2 nombres soit réel. Il faut donc écrire (/ 5 2.0) pour avoir 2.5

 

Amicalement

Vincent

C'est au pied du mur que l'on reconnaît le maçon ! (Anonyme)

C’est en restant au pied du mur qu’on ne voit que le mur (Anonyme aussi)

Lien vers le commentaire
Partager sur d’autres sites

entmake, entmakex, entmod (petit décryptage)

 

- La création de calque implicite

 

Lors de la création ou la modification d'entités, il n'est pas indispensable de créer préalablement le calque de destination de l'entité, car ces trois fonctions créent de façon implicite le calque de destination d'une entité graphique, s'il n'est pas présent dans le dessin.

 

Ex: Création d'un cercle sur le calque "MonCercle".

(entmake (list '(0 . "CIRCLE")
       '(8 . "MonCercle")
       (cons 10 (setq cen (getpoint "\nCentre du cercle: ")))
       (cons 40 (getdist cen "\nEntrez le rayon: "))
 )
)

 

 

- Code DXF en doublon lors de la construction d'une liste de définition d'entité

 

Lors de la construction d'une liste de définition d'entité, dans le cas de code en doublon c'est le dernier code de groupe qui est mémorisé les précédents sont ignoré…

 

Ex: Création d'une ligne avec 2 codes 62 (couleur) et 2 codes 8 (calque)

(entget (entmakex (list '(0 . "LINE")
                       '(8 . "0")
                       (cons 10 (setq pt (getpoint)))
                       '(62 . 5)
                       (cons 11 (getpoint pt))
                       '(62 . 3)
                       '(8 . "MaLigne")
                 )
       )
)

((-1 . <Nom d'entité: 7d549110>) (0 . "LINE") (330 . <Nom d'entité: 7d464cf8>) (5 . "11CF7A") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "MaLigne") (62 . 3) (100 . "AcDbLine") (10 32446.8 27347.6 0.0) (11 31111.1 30231.9 0.0) (210 0.0 0.0 1.0))

Seul la dernière entré pour le code 62 et 8 a été retenu

 

 

- Application à la fonction entmod

 

De ce qui précède, on comprend mieux pourquoi il est possible de modifier une définition d'entité seulement par ajout de propriétés à la définition existante. Sans passer par la fonction de substitution subst et sans devoir tester la présence ou non de codes DXF facultatif.

 

Ex: Modification du calque, de la couleur et des coordonnées d'un sommet de la ligne précédemment dessiné par ajout au moyen de la fonction append des nouvelles définitions

(entmod
 (append (entget (entlast))
  (list '(62 . 7) '(8 . "MonNouveauCalque") (cons 10 (getpoint)))
 )
)

 

Attention toutefois à la valeur de retour qui correspond à la liste transmis en argument et pas forcément à la nouvelle définition de l'entité..

_$ (entget (entlast))

 

((-1 . <Nom d 'entité: 7d549110>) (0 . "LINE") (330 . <Nom d 'entité: 7d464cf8>) (5 . "11CF7A") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "MonNouveauCalque") (62 . 7) (100 . "AcDbLine") (10 36352.5 18939.2 0.0) (11 31111.1 30231.9 0.0) (210 0.0 0.0 1.0))

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

  • 3 mois après...

Les fonctions vlax-*

 

Comme rappelé dans ce sujet

Les fonctions vlax-* se partagent entre fonctions d'accès à Microsoft (et AutoCAD) ActiveX Automation et fonctions directement issues d'ObjectARX (vlax-curve-* et vlax-ldata-*).

Les fonctions vlax- peuvent se classer en 2 types, pour les secondes (c.a.d. celles qui ne font pas explicitement appel à l'interface COM) il peut être utile de préciser qu'il est tout à fait possible de les appeler avec les types ENAME ouVLA-OBJECT (contrairement à ce que peut laisser penser l'aide).

 

Exemple:

 (setq ent (entmakex '((0 . "CIRCLE") (10 0.0 0.0 0.0) (40 . 10.0)))
     obj (vlax-ename->vla-object ent)
) 

_$ (vlax-curve-getArea ent)
314.159
_$ (vlax-curve-getArea obj)
314.159

 

Si l'on s'attache aux détails, on s'aperçoit qu'en cas de choix la première écriture est à préférer, car en interne dans ces fonctions c'est le type ENAME qui est privilégié.. :rolleyes:

_$ (benchmark '((vlax-read-enabled-p ent) (vlax-read-enabled-p obj)))
Benchmarking ...................Elapsed milliseconds / relative speed for 65536 iteration(s):
   (vlax-read-enabled-p ENT).....1186 / 2.04 <fastest>
   (vlax-read-enabled-p OBJ).....2418 / 1 <slowest>

_$ (benchmark '((vlax-curve-getEndPoint ent) (vlax-curve-getEndPoint obj)))
Benchmarking ...................Elapsed milliseconds / relative speed for 65536 iteration(s):
   (vlax-curve-getEndPoint ENT).....1357 / 1.98 <fastest>
   (vlax-curve-getEndPoint OBJ).....2683 / 1 <slowest> 

 

Liste de fonctions vlax- supportant le type ENAME:

vlax-curve-getPointAtParam

vlax-curve-getClosestPointTo

vlax-curve-getArea

vlax-curve-getSecondDeriv

vlax-curve-getPointAtDist

vlax-curve-getDistAtParam

vlax-curve-getDistAtPoint

vlax-curve-getStartPoint

vlax-curve-getClosestPointToProjection

vlax-curve-getFirstDeriv

vlax-curve-getEndParam

vlax-curve-getParamAtDist

vlax-curve-getStartParam

vlax-curve-getParamAtPoint

vlax-curve-isPeriodic

vlax-curve-isClosed

vlax-curve-isPlanar

vlax-erased-p

vlax-ename->vla-object

vlax-read-enabled-p

vlax-write-enabled-p

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

  • 9 mois après...

Bonjour,

 

(length nil) renvoie 0, puisque nil est considéré comme une liste vide.

 

(sslength nil) renvoie une erreur, nil n'est pas un jeu de sélection.

 

Il faut donc se méfier quand on fait quelque chose du genre :

 

(repeat (sslength js)

...

)

 

et vérifier en amont que le ssget qui a créé js a bien donné autre chose que nil.

 

Amicalement

Vincent

C'est au pied du mur que l'on reconnaît le maçon ! (Anonyme)

C’est en restant au pied du mur qu’on ne voit que le mur (Anonyme aussi)

Lien vers le commentaire
Partager sur d’autres sites

  • 6 ans après...

 Les fonctions  max & min

Pour mémoire, une petite subtilité avec ces 2 fonctions que j'avais oublié de relever ici:

Appelé sans arguments, elles retournent toutes les 2 deux 0

_$ (min)
0
_$ (max)
0

Appelé avec des arguments valant nil, elles retournent une erreur

_$ (min nil)
; erreur: type d'argument incorrect: numberp: nil
_$ (max nil nil nil)
; erreur: type d'argument incorrect: numberp: nil

Par analogie on comprend mieux pourquoi:

Appliqué sur une liste vide les fonctions retourne 0 (un exemple d'application ici )

_$ (apply 'min nil)
0
_$ (apply 'max nil)
0

Et qu'appliqué à une liste d'élément vide ces fonctions retourne une erreur

_$ (apply 'min '(nil nil nil))
; erreur: type d'argument incorrect: numberp: nil

 

  • Upvote 1

Apprendre => Prendre => Rendre

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é