| | | Gut zu wissen: Hilfreiche Tipps und Tricks aus der Praxis prägnant, und auf den Punkt gebracht für Autodesk Produkte | | | | PNY wird von NVIDIA zum Händler des Jahres gewählt – zum dritten Mal in Folge, eine Pressemitteilung
|
Autor
|
Thema: Runden von einer reellen Zahl in Gazzahl (4867 mal gelesen)
|
Manuel Sauter Mitglied
Beiträge: 28 Registriert: 29.10.2003
|
erstellt am: 28. Jun. 2004 14:38 <-- editieren / zitieren --> Unities abgeben:
Hallo Zusammen, habe folgendes Problem! Die beiden Variablen nBelBrW1 und nBelBrW2 werden berechnet und anschließend unter einen neuen Variable in eine Ganzzahl geändert. (setq nBelBrW1 (- (+ nWst2 iIes ) iAes) nBelBrW2 (- (+ nWst1 iIes ) iAes) eBelBrW1 (fix nBelBrW1) eBelBrW2 (fix nBelBrW2) ) Bei der Überprüfung der Variablen nBelBrW1 und nBelBrW2 werden z.B die Werte 750.0 für beide Variablen angezeigt. Bei der Überprüfung der Variablen eBelBrW1 und eBelBrW2 bekomme ich folgendes Ergebnis: eBelBrW1 = 750 eBelBrW2 = 749 Es ist mir unerklärlich wie die 749 zustande kommt. Die geschieht auch nicht jedesmal bei dem Durchlauf der Routine. Mache ich einen Fehler, oder verstehe ich den Befehl "fix" nicht richtig? Hat jemand vielleicht mal ein ähnliches Problem? Gruß Manuel Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Brischke Moderator CAD on demand GmbH
Beiträge: 4187 Registriert: 17.05.2001 AutoCAD 20XX, defun-tools (d-tools.eu)
|
erstellt am: 28. Jun. 2004 14:51 <-- editieren / zitieren --> Unities abgeben: Nur für Manuel Sauter
Hallo Manuel, die Funktion fix schneidet einfach die Nachkommastellen ab. Wenn also die berechnete Zahl nicht exakt oder größer 750 ist, dann kommt es zu dieser Erscheinug. Du solltest also auch die Nachkommastellen prüfen. um dann zu entscheiden, ob auf oder abgerundet wird. Nachkommastellen = Zahl - fix(Zahl) Grüße Holger ------------------ Holger Brischke (defun - Lisp over night! AutoLISP-Programmierung für AutoCAD Da weiß man, wann man's hat! Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Manuel Sauter Mitglied
Beiträge: 28 Registriert: 29.10.2003
|
erstellt am: 28. Jun. 2004 15:16 <-- editieren / zitieren --> Unities abgeben:
Hallo Holger, ich möchte garnicht Runden, sonder nur die Nachkommastellen weg haben. In diesem Falle verstehe ich den Befehl "fix" schon richtig. Wie oben schon geschrieben bekomme ich aber aus dem Wert 750.0, der berechnet wurde, über den Befehl "fix" manchmal den Wert 749! Über den Visual Lisp Editor habe ich mir immer die Werte von nBelBrW1 und nBelBrW2 anzeigen lassen. Die sind jedesmal 750.0. Die Werte eBelBrW1 oder eBelBrW2 sind aber manchmal 749. Das darf doch nicht sein, oder?
Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Ex-Mitglied
|
erstellt am: 28. Jun. 2004 15:29 <-- editieren / zitieren -->
Zitat: Original erstellt von Manuel Sauter: ich möchte garnicht Runden, sonder nur die Nachkommastellen weg haben.
Nein, ich glaube nicht, dass Du das wirklich willst :-) "Reelle" Zahlen gibt's auf Computern nicht wirklich, denn zu deren Darstellung würden wir exakt unendlich viel Speicher benötigen. Statt dessen verwenden wir prinzipiell nur näherungsweise Dezimalzahlen mit endlicher Genauigkeit, und dadurch kann es nach einer Anzahl von Rechenoperationen schon mal vorkommen, dass ein Ergebnis nicht mathematisch korrekt 750.0 ergibt, sondern 749.999999999999998. Und wenn Du von 749.999999999999998 mittels FIX die Nachkommastellen abschneidest, kriegst Du auch das korrekte Ergebnis 749 raus. Du willst also tatsächlich erst auf beispielsweise 10 Nachkommastellen runden, und willst davon erst die Nachkommastellen abschneiden. Zitat: Das darf doch nicht sein, oder?
Ich hoffe, Du verstehst jetzt, warum das sogar so sein MUSS. Tom Berger
------------------
|
mapcar Mitglied CADmin
Beiträge: 1250 Registriert: 20.05.2002 Time flies like an arrow, fruit flies like a banana (Groucho Marx)
|
erstellt am: 28. Jun. 2004 16:12 <-- editieren / zitieren --> Unities abgeben: Nur für Manuel Sauter
|
Dabrunz Mitglied
Beiträge: 127 Registriert: 28.05.2003
|
erstellt am: 28. Jun. 2004 16:19 <-- editieren / zitieren --> Unities abgeben: Nur für Manuel Sauter
Tom hat völlig recht, das muss so sein. Ist allerdings ein wenig unbefriedigend oder? Ich mach' hier mal ein Beispiel, das sehr schön illustriert wo dir Krux dieser Verhaltensweise konkret liegt: Code:
(fix(/ 5.6 0.7)) -> 8 wunderbar, alles klar(fix(/ 5.6 0.8)) -> 6 oops ..
Wie bereits festgestellt, liegt das an der internen Iplementierung von Floatingpoint-Darstellungen die ist bekannter Weise recht ungenau, weil im Binär-System abgeschnitten wird, aber nicht Dezimal, wie wir das gewohnt sind. Zahlen, die sich wunderbar im Dezimal-System darstellen lassen (z.B. 0.8) kann ich als Binär-Bruch nur runden, wie es mit den Dezimal-Brüchen der Fall ist bei 1/7 (die Dezimal-Bruch-Darstellung hierfür sieht z.B. so aus: 0.142857 das ist aber mit Sichheit nicht 1/7). Da ist also nix zu machen .. Blöde ist, dass das Beispiel oben ohne fix ganz vertrauenswürdig aussieht: Code:
(/ 5.6 0.7) -> 8.0 (/ 5.6 0.8) -> 6.0
Das liegt daran, dass AutoCAD beim Darstellen der Zahlen auf seine Zeichenketten-Umwandlung zurück greift und die nicht nur abschneidet. Es wird uns also etwas anderes angezeigt, als ausgerechnet .. blöde. Deshalb gibt's da einen üblen Hack, der aber das tut was wir (vielleicht) wollen - jedenfalls benutze ich ihn, wenn ich Ganzzahl-Rundungen brauche: Code:
(defun :fix (#val) (setq #val (vl-princ-to-string #val)) (if (distof #val) (atoi #val) ) )
Wer mag, soll hiermit glücklich werden. Achim Dabrunz Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
mapcar Mitglied CADmin
Beiträge: 1250 Registriert: 20.05.2002 Time flies like an arrow, fruit flies like a banana (Groucho Marx)
|
erstellt am: 28. Jun. 2004 16:39 <-- editieren / zitieren --> Unities abgeben: Nur für Manuel Sauter
|
Manuel Sauter Mitglied
Beiträge: 28 Registriert: 29.10.2003
|
erstellt am: 28. Jun. 2004 16:43 <-- editieren / zitieren --> Unities abgeben:
|
Ex-Mitglied
|
erstellt am: 28. Jun. 2004 17:36 <-- editieren / zitieren -->
Zitat: Original erstellt von Dabrunz: Deshalb gibt's da einen üblen Hack, der aber das tut was wir (vielleicht) wollen - jedenfalls benutze ich ihn, wenn ich Ganzzahl-Rundungen brauche:Code:
(defun :fix (#val) (setq #val (vl-princ-to-string #val)) (if (distof #val) (atoi #val) ) )
vl-princ-to-string ist oft nicht so hilfreich, weil hier die Genauigkeit an die Anzeigegenauigkeit gekoppelt ist und IIRC maximal 8 Dezimalstellen beträgt. RTOS hängt wiederum von Systemvariablen wie DIMZIN ab, die einfach durch einen Wechsel eines Bemaßungsstils verstellt werden. Blieb also nur die Programmierung einer eigenen AT-RTOS Funktion übrig: (defun at-rtos (zahl modus genau / result olddimzin) (setq olddimzin (getvar "DIMZIN")) (setvar "DIMZIN" 8) (setq result (rtos zahl modus genau)) (setvar "DIMZIN" olddimzin) (if (and (= 'INT (type (read result))) (/= 0 genau) ) (setq result (strcat result ".0")) ) result ) Das nenne ich nun wirklich einen üblen Hack (man beachte die "Umrechnung" eines unerwünschten INT-Ergebnisses in einen String, der eine Fliesskommazahl enthält), aber mir ist bis heute noch nichts Besseres eingefallen, und ich verwende AT-RTOS ausnahmslos dort, wo andere Leute nur RTOS verwenden: Befehl: (setq zahl 749.9999999999998) 750.0 Befehl: (= zahl 750.0) nil Befehl: (= (read (at-rtos zahl 2 10)) 750.0) T Gruß Tom Berger ------------------
|
Ex-Mitglied
|
erstellt am: 28. Jun. 2004 17:54 <-- editieren / zitieren -->
Zitat: Original erstellt von mapcar: Und hier noch ein kleines Beispiel zum Nachdenken: [...]
Da fällt mir noch eine Anekdote ein, die an dieser Stelle unbedingt erzählt werden muss - schliesslich hat die ESA über 5 Milliarden Euro dafür ausgegeben, dass Informatik-Studenten 1A-Anschauungsmaterial für das Thema "Fliesskommaüberlauf" erhalten :-) Die allererste Ariadne 5 war eigentlich schon ein Meisterwerk, dumm nur, dass der Navigationscomputer versagt hat. Noch dümmer: der Navigationscomputer samt Software war identisch mit dem, der in der Ariadne 4 schon zigmal allerbestens funktioniert hat. Man hat dieses System ganz bewußt ohne jede Änderung aus der Ariadne 4 in die Ariadne 5 übernommen, weil man wusste: never change a runnig system. Der Haken war halt, dass die Ariadne 5 ziemlich viel schwerer ist als die Ariadne 4, und dass ein schon immer in der Software vorhandener Bug sich bei der leichteren Rakete nicht auswirkte. Bei der Ariadne 5 aber gab's wegen des höheren Gewichts einen Fliesskommaüberlauf, der den Computer dazu brachte, die Rakete um 180 Grad herum zu steuern. Also nach unten statt nach oben :-) Gruß Tom Berger
------------------
|
CADmium Moderator Maschinenbaukonstrukteur
Beiträge: 13527 Registriert: 30.11.2003 .
|
erstellt am: 28. Jun. 2004 19:38 <-- editieren / zitieren --> Unities abgeben: Nur für Manuel Sauter
..und nochwas ohne Typumwandlung .. wenn auch ein wenig länger (defun ROUND (ZAHL STELLEN / TEMP ) (if (and(numberp ZAHL) (=(type STELLEN) 'INT)) (progn (setq TEMP (abs ZAHL)) (repeat STELLEN (setq TEMP (* TEMP 10.0))) (cond ( (> (- TEMP (fix TEMP)) 0.5) (setq TEMP (+ (fix TEMP) 1))) ( (< (- TEMP (fix TEMP)) 0.5) (setq TEMP (fix TEMP) )) ( (= (- TEMP (fix TEMP)) 0.5) (if (equal (/ (fix TEMP) 2.0) (fix(/ (fix TEMP) 2.0)) 0.001) (setq TEMP (fix TEMP) ) (setq TEMP (+ (fix TEMP) 1)) ) ) ) (repeat STELLEN (setq TEMP (/ TEMP 10.0))) (setq TEMP (* TEMP (if (< Zahl 0 ) -1.0 1.0))) ) ) TEMP ) .. kann auch erweitert werden auf runden auf vielfaches von X usw. mal als Anstoß für eine algemeinere Funktion. ------------------ - Thomas - Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
| Anzeige.:
Anzeige: (Infos zum Werbeplatz >>)
|