Umgang mit Rundungsfehler
-
Nein, 1.00000000002 ist > 1. Punkt. Nichts weiter zu diskutieren. Beziehungsweise es gäbe zu diskutieren, was du da tust (oder besser: was du wirklich erreichen möchtest), dass du denkst, du bräuchtest das anders. Denn es sind gewiss komische Anforderungen (oder ein Missverständnis), dass zu einer Anforderung führt, bei der 1.00000000002 <= 1 sein soll.
Leite ich mir das richtig her: Du möchtest gucken, ob/wo zwei Geraden sich schneiden, aber hast nun Angst, dass die Geraden sich nicht/anderswo schneiden, als du denkst? Aber die Rechnung (sofern korrekt programmiert) wäre ja richtig: Wenn deine Gerade eine Steigung 0.1000000000021 hat statt 0.1, dann ist das Ergebnis halt ein anderes als du denkst, aber dieses Ergebnis ist trotzdem richtig (für 0.1000000000021). Das heißt, entweder passen deine Erwartungen nicht, oder deine Anforderungen sind andere und du hast den falschen Weg gewählt. Wenn deine Anforderung war "es soll das exakte Ergebnis für alle Werte rauskommen, die man im Dezimalsystem tippen kann", dann passt deine Umsetzung nicht dazu. Dann können wir darüber reden, wie man die besser/korrekt umsetzen kann (aber erwarte nicht, dass so etwas einfach wird!)
-
@SeppJ sagte in Umgang mit Rundungsfehler:
Nein, 1.00000000002 ist > 1. Punkt. Nichts weiter zu diskutieren. Beziehungsweise es gäbe zu diskutieren, was du da tust (oder besser: was du wirklich erreichen möchtest), dass du denkst, du bräuchtest das anders. Denn es sind gewiss komische Anforderungen (oder ein Missverständnis), dass zu einer Anforderung führt, bei der 1.00000000002 <= 1 sein soll.
Also gut , ich habe eine weitere Funktion welche den Schnittpunkt zweier"Strecken" berechnet:
a = 0/0
b = 100/100
c = 0/200
d = 0,0001/0,0001BOOL intersect_line_with_line2(point_t* A, point_t* B, point_t* C, point_t* D, point_t* out) { // float s1_x, s1_y, s2_x, s2_y; FLOAT_t s1_x = B->x - A->x; FLOAT_t s1_y = B->y - A->y; FLOAT_t s2_x = D->x - C->x; FLOAT_t s2_y = D->y - C->y; FLOAT_t d = (-s2_x * s1_y + s1_x * s2_y); /* if 0 == parallel */ // if (!compare(d, 0)) if (!isnan(d)) { /* line parameter */ FLOAT_t s = (-s1_y * (A->x - C->x) + s1_x * (A->y - C->y)) / d; FLOAT_t t = (s2_x * (A->y - C->y) - s2_y * (A->x - C->x)) / d; // if (s >= 0.0 && s <= 1.0 && t >= 0.0 && t <= 1.0) { /* Collision detected */ out->x = A->x + (t * s1_x); out->y = A->y + (t * s1_y); return TRUE; } } out->x = 0; out->y = 0; return FALSE; // No collision }
und die strecken müssen sich definit schneiden, aber s ist hier 1.0000000000000002! das is das problem;)
-
Ich habe oben noch eine Rückfrage zu den genauen Anforderungen reineditiert, wo mich deine Antwort interessieren würde.
Problem hier ist halt (ich prüfe jetzt nicht deine Rechnung, ob die wirklich stimmt), dass (float) 0,0001 nicht das ist, was du denkst, und sich deine Strecken halt mathematisch nicht schneiden, mit dem Wert, der 0,0001 in Wirklichkeit ist. Da ist halt jetzt die Frage, was du wirklich genau willst, siehe meinen Edit oben zu den genauen Anforderungen.
-
PS: Da ist jetzt auch wirklich wichtig, dass du nicht einfach blind Anforderungen formulierst, die möglichst genau klingen. Denk darüber nach, warum du etwas brauchst und was du damit machst. Wenn du das Ergebnis beispielsweise in einem Programm benutzt, das auch in Flieskommazahlen rechnet und wissen muss, ob sich zwei solche Strecken schneiden, dann ist das derzeit ja schon richtig; die Strecken schneiden sich nicht (vorausgesetzt deine Rechnung stimmt, was ich nicht geprüft habe) mit diesen Fließkommazahlen als Eingabe und es ist völlig egal, dass es in der Nähe andere Werte gäbe, bei denen sie sich schneiden. Wenn du ein CAS schreibst, ist es hingegen tatsächlich nicht korrekt, aber die genauen Anforderungen an ein CAS sind halt auch nicht so einfach zu formulieren.
-
@SoIntMan Das Literal 1.0 ist in C erstmal ein double.
Wenn du float möchtest, schreib 1.0fDas ist die 1, die float hergibt.
-
@SeppJ sagte in Umgang mit Rundungsfehler:
PS: Da ist jetzt auch wirklich wichtig, dass du nicht einfach blind Anforderungen formulierst, die möglichst genau klingen. Denk darüber nach, warum du etwas brauchst und was du damit machst. Wenn du das Ergebnis beispielsweise in einem Programm benutzt, das auch in Flieskommazahlen rechnet und wissen muss, ob sich zwei solche Strecken schneiden, dann ist das derzeit ja schon richtig; die Strecken schneiden sich nicht (vorausgesetzt deine Rechnung stimmt, was ich nicht geprüft habe) mit diesen Fließkommazahlen als Eingabe und es ist völlig egal, dass es in der Nähe andere Werte gäbe, bei denen sie sich schneiden. Wenn du ein CAS schreibst, ist es hingegen tatsächlich nicht korrekt, aber die genauen Anforderungen an ein CAS sind halt auch nicht so einfach zu formulieren.
Guten Morgen Sepp,
nun allein durch die Erkenntnis welche ich hier und bei meinem Vorhaben erlangt habe, und ich von der Kopf-Unendliche Genauigkeit weg muss. Wären meine Anforderungen für die wie folgt:
Die Punkte der Linen/Geraden sollen frei im Raster 0,00001 gesetzt werden können, in einem Kartesischen Raum -1.000.000 <= (x/y) <= 1.000.000.
@DirkB sagte in Umgang mit Rundungsfehler:
@SoIntMan Das Literal 1.0 ist in C erstmal ein double.
Wenn du float möchtest, schreib 1.0f
Das ist die 1, die float hergibt.Danke dir , hinter dem FLOAT_t verbirgt sich ein double;)
-
@SoIntMan sagte in Umgang mit Rundungsfehler:
Die Punkte der Linen/Geraden sollen frei im Raster 0,00001 gesetzt werden können, in einem Kartesischen Raum -1.000.000 <= (x/y) <= 1.000.000.
Hast du da jetzt wirklich drüber nachgedacht? Denn es sieht aus wie fix ausgedacht. Hast du wirklich einen Grund für 0.00001 statt 0.00001525878? (Die Zahl 0.00001525878 ist kein Zufall und solltest du wiedererkennen, wenn du wirklich nachgedacht hast). Warum 1,000,000 statt beispielsweise 1,048,576? Hast du einen Grund für das fixe Raster? Hast du über die Definitionen von Strecken und Schnittpunkten auf einem Raster nachgedacht?
-
@SeppJ sagte in Umgang mit Rundungsfehler:
Hast du da jetzt wirklich drüber nachgedacht? Denn es sieht aus wie fix ausgedacht. Hast du wirklich einen Grund für 0.00001 statt 0.00001525878? (Die Zahl 0.00001525878 ist kein Zufall und solltest du wiedererkennen, wenn du wirklich nachgedacht hast). Warum 1,000,000 statt beispielsweise 1,048,576? Hast du einen Grund für das fixe Raster? Hast du über die Definitionen von Strecken und Schnittpunkten auf einem Raster nachgedacht?
Du hast mich ertappt;) nein so genau habe ich nicht nachdacht. Stellt dir vor du hast ein Polygon mit N-Vertices. Welche willkürliche punkte haben können, aber da diese sich ja auch im selben Wertesystem befinden und ich bspw. random die punkte willkürlich bestimmte, können diese punkte jauch nicht 0.00001 sein sonder 0.00001525878 !? oder?
Wie gehe ich da nun vor?
-
@SeppJ sagte in Umgang mit Rundungsfehler:
Warum 1,000,000 statt beispielsweise 1,048,576?
ja eigentich is das sogar + - beliebigt.. aber gröér kleiner ~1.000.000 past
@SeppJ sagte in Umgang mit Rundungsfehler:
Hast du einen Grund für das fixe Raster?
naja da ganze ist für eine Simulation welche 0,00001 mm genau sein soll...
-
@SoIntMan sagte in Umgang mit Rundungsfehler:
Stellt dir vor du hast ein Polygon mit N-Vertices.
[…]
naja da ganze ist für eine Simulation welche 0,00001 mm genau sein soll...Jetzt kommen wir langsam irgendwohin. Das klingt mal so langsam nach einer echten Anforderung. Erklär mal mehr!
Wenn deine Genauigkeit 0.00001 sein soll, sollte deine Rechnung meistens feiner sein, kommt aber drauf an. Verdächtig ist aber auch, dass du andererseits die Obergrenze 1,000,000 nennst. Das sind 11 Größenordnungen. Die genaueste Messungen, die die Menschheit bisher jemals durchgeführt hat, sind auf ca 13-15 Stellen genau. Arbeitest du wirklich in so einem Bereich, oder ist das auch wieder nur willkürlich aus der Luft gezogen?
-
@SeppJ sagte in Umgang mit Rundungsfehler:
Jetzt kommen wir langsam irgendwohin. Das klingt mal so langsam nach einer echten Anforderung. Erklär mal mehr!
Wenn deine Genauigkeit 0.00001 sein soll, sollte deine Rechnung meistens feiner sein, kommt aber drauf an. Verdächtig ist aber auch, dass du andererseits die Obergrenze 1,000,000 nennst. Das sind 11 Größenordnungen. Die genaueste Messungen, die die Menschheit bisher jemals durchgeführt hat, sind auf ca 13-15 Stellen genau. Arbeitest du wirklich in so einem Bereich, oder ist das auch wieder nur willkürlich aus der Luft gezogen?Hey, ok dann lass die Obergrenze einfach weg, ist erstmal auch nicht wichtig (willkürlich). Anhand von einem Formel/Funktion wird ein Polygon berechnet. eine art Arc.segment bestehend aus n Line Segmenten.. ich denke durch Sin/cos kommen dann auch ganz wilde zahlen raus. Ich kann die Ergebnisse dann auch runden, das wäre natürlich hein ansatz, So ganz tief habe ich das noch nicht evaluiert, aber auch 0,001 wäre noch ok. muss ich noch klären;)
Aber jetzt hab ich sogar noch eine weiter frage. ich habe eine Slope funktion welche mir die Steigung eine line zwischen zwei punkten berchenet:
double slope = (a->y - b->y) / (a->x - b->x);
wenn ich nun 2 punkte paare einsetze
A: 300/400 B:300/300 => Slope -0
A: 300/400 B:300/600 => Slope +0Wenn ich die beiden slopes vergleiche kommt true raus, aber eigenlich sollte es falsch sein wegen dem vorzeichen;) dann hab ich auf das erste bit geschaut:
BOOL X1 = (BOOL)((int32_t)slopeA & 0x80000000); BOOL X2 = (BOOL)((int32_t)slopeB & 0x80000000); BOOL X3 = (BOOL)((int32_t)slopeA & 0x1); BOOL X4 = (BOOL)((int32_t)slopeB & 0x1);
aber hmm immer 0 !? zu blauäugig? bekomme ich das überhaupt raus?
-
Aber wozu ist das alles gut? Ist das eine Simulation wo Polygone durch die Gegend fliegen und du willst ausrechnen, ob sie sich stoßen?
Wenn ich die beiden slopes vergleiche kommt true raus, aber eigenlich sollte es falsch sein wegen dem vorzeichen;)
Wieso soll 0 nicht 0 sein?
-
@SeppJ sagte in Umgang mit Rundungsfehler:
Wieso soll 0 nicht 0 sein?
weil die steigung zwar jeweils 0 sind aber einmal nach recht oder nach links driften;)
Laut debugger seh ich auch 0.00000000 bzw. -0.000000000. müsste ja ein sign bit sein p.s. sollte auch int64_t nehme aber kein bit
-
@SeppJ sagte in Umgang mit Rundungsfehler:
Aber wozu ist das alles gut? Ist das eine Simulation wo Polygone durch die Gegend fliegen und du willst ausrechnen, ob sie sich stoßen?
ne ich schieße ein paar rays , linen durch und will auch sicherstellen dass sie treffen wo sie treffen sollen;)
-
Das ist aber nicht, was du berechnest. Die Steigung ist schließlich 0. Würde dir jedes Grundschulkind so ausrechnen und bestätigen können, dass die beide 0 sind.
Es gibt Funktionen in C, die dir das Vorzeichen korrekt liefern, ohne dich auf wilde Casts verlassen zu müssen. Aber wie gesagt, ist da eher ein Fehler in deiner Logik, dass du nicht die richtige Rechnung machst zu der Frage, die du beantworten willst.
@SoIntMan sagte in Umgang mit Rundungsfehler:
ne ich schieße ein paar rays , linen durch und will auch sicherstellen dass sie treffen wo sie treffen sollen;)
Bitte genauer! Was meinst du mit "sollen"?
-
@SeppJ sagte in Umgang mit Rundungsfehler:
Das ist aber nicht, was du berechnest. Die Steigung ist schließlich 0. Würde dir jedes Grundschulkind so ausrechnen und bestätigen können, dass die beide 0 sind.
Es gibt Funktionen in C, die dir das Vorzeichen korrekt liefern, ohne dich auf wilde Casts verlassen zu müssen. Aber wie gesagt, ist da eher ein Fehler in deiner Logik, dass du nicht die richtige Rechnung machst zu der Frage, die du beantworten willst.du hast recht..
@SeppJ sagte in Umgang mit Rundungsfehler:
Bitte genauer! Was meinst du mit "sollen"?
weil es sonst falsch wäre? wenn da ein schnittpunkt ist?
-
@SoIntMan sagte in Umgang mit Rundungsfehler:
@SeppJ sagte in Umgang mit Rundungsfehler:
Bitte genauer! Was meinst du mit "sollen"?
weil es sonst falsch wäre? wenn da ein schnittpunkt ist?
(Floating point-)arithmetisch ist da ja kein Schnittpunkt…
Da ich nicht die Antwort bekomme, die ich brauche, und du wahrscheinlich genauso genervt bist von meinen dauernden Gegenfragen: Ich will wissen, was du erreichen willst. Ganz weit weg von allen deinen konkreten Problemen mit Schnittpunkten und Steigungen. Nicht wie du es machst; nicht was deine Probleme dabei sind; nicht wie du denkst, dass das geht. Klassisches XY-Problem. Ich bin nämlich ziemlich sicher, dass du wahrscheinlich gar kein Problem hast, sondern dir nur selber eines einredest. Aber es gäbe auch genügend Fälle, wo du tatsächlich ein Problem haben könntest und die Lösung ganz woanders liegt, daher mag ich das auch nicht pauschal behaupten, ohne den genauen Anwendungsfall zu kennen.
-
@SeppJ sagte in Umgang mit Rundungsfehler:
Da ich nicht die Antwort bekomme, die ich brauche, und du wahrscheinlich genauso genervt bist von meinen dauernden Gegenfragen: Ich will wissen, was du erreichen willst. Ganz weit weg von allen deinen konkreten Problemen mit Schnittpunkten und Steigungen. Nicht wie du es machst; nicht was deine Probleme dabei sind; nicht wie du denkst, dass das geht. Klassisches XY-Problem. Ich bin nämlich ziemlich sicher, dass du wahrscheinlich gar kein Problem hast, sondern dir nur selber eines einredest. Aber es gäbe auch genügend Fälle, wo du tatsächlich ein Problem haben könntest und die Lösung ganz woanders liegt, daher mag ich das auch nicht pauschal behaupten, ohne den genauen Anwendungsfall zu kennen.
ja schwierig.. wir sollten mal ein Bier trinken:) naja ich mach mir nochmal Gedanken..