Precizie cu AutoLISP

de Albert Kalman

motto - Păi, dacă ista nu știe să calculeze corect 3.8/0.1 atunci la ce-i bun ?

Așa după cum știm în AutoCAD (mai puțin AutoCAD LT), avem la dispoziție un limbaj de programare numit AutoLISP. Prin intermediul acestui limbaj, AutoCAD-ul se deosebește de celelalte soluții CAD prin faptul că ne poate oferi un mijloc ușor, simplu și ieftin pentru a ne crea mici rutine dar și aplicații complexe ce ne pot ajuta în activitatea de proiectare de zi cu zi.

În articolul de față, vom aborda precizia de calcul cu AutoLISP-ul.

Numere reale

Toate numerele reale în AutoCAD și AutoLISP sunt stocate intern ca numere reale în dubla precizie. În paranteză, vom aminti că, în cazul limbajelor de programare, în general, orice variabilă ce se definește trebuie să i se indice și ce fel de tip este: întreg, real, simplă precizie sau dublă precizie, șir, etc. Stocarea în dublă precizie înseamnă calcule cu mai mult de 14 zecimale.

AutoLISP-ul garantează calcularea valorilor cu până la 14 zecimale exacte. Aceste 14 zecimale sunt limitate de hard și de metodele adoptate pentru calcul și nu însăși de AutoCAD și de AutoLISP, și, de aceea, calculele ce se fac cu numere reale ce depășesc 14 zecimale pot produce rezultate eronate.

Ca să exemplificăm ce înseamnă numere reale cu 14 zecimale, să considerăm desenul unei hărți la scară de 1:1. Dacă limitele sunt între 2800 și 700 de kilometri, asta înseamnă că pe harta digitală vom putea crea geometri cu o acuratețe de 0.00001 milimetri. Prin urmare, se pune întrebarea dacă alte programe de CAD oferă un suport atât de precis de calcul? Pe de altă parte, unele din programele CAD sunt bazate pe calculul numerelor întregi și sunt departe de precizia oferită de AutoCAD și AutoLISP.

Concluzia este că un calcul cu precizie de 14 este acoperitor.

AutoLISP

Observația cea mai importantă și care îi privește pe programatori este că AutoLISP-ul afișează doar 6 zecimale semnificative ale unui număr real. Astfel, dacă o variabilă are valoarea de 1.123456789 în LISP, ea va fi afișată ca 1.12346! care nu pare a fi foarte precis. Pentru a putea afișa un număr real cu toate zecimalele, se folosește funcția RTOS care transformă un număr real într-un șir. Să facem un exemplu concret:

Pe linia de comandă AutoCAD (sau dacă folosim Visual LISP, direct în consolă):

(setq a 1.123456789) se returnează 1.12346

!a rezultă 1.12346

(rtos A 2 12) se returnează 1.123456789000

Atenție: în caseta ddim la opțiunea Annotation și apoi Units se va deselecta opțiunea Trailing, după care se va salva stilul de cotare.

Așa după cum vedem, funcția rtos afișează numărul real cu toate zecimalele dar și cu zerouri nesemnificative, deoarece s-a cerut afișarea cu mai multe zecimale decât avea numărul.

Să vedem ce se întâmplă atunci când folosim funcția equal. Funcția Equal compară două elemente (argumente), în limita unui coeficient de aproximare. Alte două funcții pot fi folosite pentru a compara două elemente și anume: = și eq.

Să luăm un exemplu:

(setq B(/3.8 0.1) returnează 38.0

(setq C 38.0) returnează 38.0

(equal b c) returnează nil

Așa după cum vedem, cele două valori ar fi egale. Să vedem variabila B cu mai multe zecimale

(rtos B 2 13)

returnează 38.0000000000000)

(rtos B 2 14)

returnează 37.99999999999999)

Adevărata valoare a variabilei B este 37.99999.... dar AutoLISP-ul afișează numai dacă valoarea este convertită într-un șir cu un număr mare de zecimale. Matematic (/ 3.8 0.1) este egal practic cu 38.0 dar, datorită algoritmilor de calcul folosiți, valoarea este alta. Nu același lucru se întâmplă cu (/ 3.7 0.1), a cărei valoare calculată de soft este 37.0.

Concluzia este că niciodată nu putem fi siguri că nu există eroare de calcul la mai mult de 14 zecimale. O soluție bună este de a compara valorile reale în limita unei aproximări care se exprimă în limbajele de programare fuzzy funcția equal pe care am amintit-o prin:

(equal b c 1e-14) returnează T

Deci, folosiți funcția equal pentru a fi siguri că rezultatele nu sunt eronate.

Fix

O altă problemă este aceea a trunchierii unui număr real, folosind funcția fix. Folosin funcția fix vom fi surprinși să constatăm că pentru exemplul de mai sus (fix b) returnează 37! și nu 38, așa cum ne-am fi așteptat. Funcția fix nu permite folosirea unui coeficient de aproximare, printr-o mică rutină, putem evita problema:

(defun ffix (a / count)

(setq a (rtos a )) ; trasnsformăm în 1șir

(setq count 1) ; contor

(while (/= "." (substr a count 1)) ; parcurge șirul pâna la punctul zecimal

(setq count (1+ count)) ; marește contorul cu 1

)

(atoi (substr a 1 (1- count))) ; extrage întregul găsit

)

(ffix b) rezultă 38


(C) Copyright Computer Press Agora