Delphi-PRAXiS
Seite 1 von 4  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Seltsames Verhalten einer Funktion (https://www.delphipraxis.net/200467-seltsames-verhalten-einer-funktion.html)

Pytroxis 24. Apr 2019 11:34

Delphi-Version: 10.2 Tokyo

Seltsames Verhalten einer Funktion
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hey,

ich bin es mal wieder, langsam verzweifle ich an Delphi :(

Bei meinem Programm werden Boxplots dargestellt/gezeichnet, prinzipiell funktioniert das auch.
Nun habe ich mich daran versucht 2 unterschiedliche Boxplots darzustellen und bin auf ein sehr großes Problem gestoßen:
Wenn beide Boxplots den gleichen Datensatz haben werden sie Normal dargestellt, sofern aber einer der Boxplots einen anderen Datensatz besitzt wird der erste nicht mehr korrekt dargestellt (siehe Anhang).
Ich habe bereits einiges getestet und bin zu folgendem Entschluss gekommen:
  • Es liegt nicht an dem sortieren /einlesen. Datensatz wird korrekt abgespeichert bzw. eingelesen und sortiert (-> Mehrfach überprüft).
  • Es muss an der Funktion für das zeichnen liegen
Ich habe die Funktion nun mehrfach neu geschrieben und auf Fehler überprüft aber ich finde einfach keinen (-> Bestimmt ein ganz simpler Fehler, den ich einfach nicht finde).

Dementsprechend hier die Funktion (bitte schlagt mich nicht für den schlechten Stil):
Delphi-Quellcode:
var
  zahlen : array of array of Double;
  namen : TStrings;
  quartils : array[0..1] of Double;
  median : Double;
  bereiche: array[0..3] of array of Double;

...

procedure drawLine(PaintBox:TPaintBox; color: TColor; minX, minY, maxX, maxY:integer);
 begin
  PaintBox.Canvas.Pen.Color := color;
  PaintBox.Canvas.MoveTo(minX, minY);
  PaintBox.Canvas.LineTo(maxX, maxY);
 end;

 procedure zeichnen(PaintBox : TPaintBox; Boxplot : real; FHeight, FWidth: Integer);
  var i, xWert, Height, index: integer;
      eineLaengeneinheit : Double;
      getHeight : array[0..9] of integer;


  begin
    if Length(zahlen) > 0 then begin
      xWert := 40;
      Height := round(FHeight * 0.4);
      index := Round(Boxplot);

      eineLaengeneinheit := (FWidth-120) / round(zahlen[index][Length(zahlen[index])-1] - zahlen[index][0]);


      getHeight[0] := round(FHeight * 0.31919 + Height * Boxplot);
      getHeight[1] := round(FHeight * 0.13214 + Height * Boxplot);
      getHeight[2] := round(FHeight * 0.18379 + Height * Boxplot);
      getHeight[3] := round(FHeight * 0.04839 + Height * Boxplot);
      getHeight[4] := round(FHeight * 0.09839 + Height * Boxplot);
      getHeight[5] := round(FHeight * 0.21839 + Height * Boxplot);
      getHeight[6] := round(FHeight * 0.15839 + Height * Boxplot);
      getHeight[7] := round(FHeight * 0.26839 + Height * Boxplot);
      getHeight[8] := round(FHeight * 0.28839 + Height * Boxplot);
      getHeight[9] := round(FHeight * 0.27839 + Height * Boxplot);

      // Name des Boxplots
      PaintBox.Canvas.TextOut(xWert-30, getHeight[3]-20, namen[index] + ':');

      // Einteilung/Markierung
        // Minimum
      PaintBox.Canvas.TextOut(xWert-3, getHeight[0], FloatToStr(zahlen[index][0]));
      drawLine(PaintBox, clRed, xWert, getHeight[1], xWert, getHeight[2]);

        // Maximum
      PaintBox.Canvas.TextOut(FWidth - 80, getHeight[0], FloatToStr(zahlen[index][Length(zahlen[index]) - 1]));
      drawLine(PaintBox, clRed, FWidth-80, getHeight[1], FWidth-80, getHeight[2]);

        // unteres Quartil
      PaintBox.Canvas.TextOut(round(xWert - 3 + (quartils[0] - zahlen[index][0]) * eineLaengenEinheit), getHeight[3], FloatToStr(quartils[0]));
      drawLine(PaintBox, clRed, round(xWert + (quartils[0] - zahlen[index][0])*eineLaengenEinheit), getHeight[4], round(xWert +
        (quartils[0] - zahlen[index][0])*eineLaengenEinheit), getHeight[5]);

        // median
      PaintBox.Canvas.TextOut(round(xWert - 3 + (median - zahlen[index][0]) * eineLaengenEinheit), getHeight[3], FloatToStr(median));
      drawLine(PaintBox, clRed, round(xWert + (median - zahlen[index][0])*eineLaengenEinheit), getHeight[4], round(xWert +
        (median - zahlen[index][0])*eineLaengenEinheit), getHeight[5]);

        // oberes Quartil
      PaintBox.Canvas.TextOut(round(xWert - 3 + (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[3], FloatToStr(quartils[1]));
      drawLine(PaintBox, clRed, round(xWert + (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[4], round(xWert +
        (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[5]);

        //Boxplot an sich
      drawLine(PaintBox, clBlack, xWert, getHeight[6], round(xWert + (quartils[0] - zahlen[index][0]) * eineLaengenEinheit), getHeight[6]);
      drawLine(PaintBox, clBlack, round(xWert + (quartils[0] - zahlen[index][0]) * eineLaengenEinheit), getHeight[4], round(xWert +
        (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[4]);
      drawLine(PaintBox, clBlack, round(xWert + (quartils[0] - zahlen[index][0]) * eineLaengenEinheit), getHeight[5], round(xWert +
        (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[5]);
      drawLine(PaintBox, clBlack, round(xWert + (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[6], FWidth - 80, getHeight[6]);

      //Skala
      for i := 0 to round(zahlen[index][Length(zahlen[index])-1]-zahlen[index][0]) do
        drawLine(PaintBox, clBlack, round(xWert + i * eineLaengenEinheit), getHeight[7], round(xWert + i * eineLaengenEinheit), getHeight[8]);
      drawLine(PaintBox, clBlack, xWert, getHeight[9], FWidth-80, getHeight[9]);
      end;
  end;
Findet ihr einen Fehler? Langsam verzweifle ich daran und kann mir nicht erklären woran es liegen kann :/ :(

hoika 24. Apr 2019 11:57

AW: Seltsames Verhalten einer Funktion
 
Hallo,
OK, für den schlechten Stil hast Du dich schon entschuldigt ;)

Aber:
for i := 0 to round(zahlen[index][Length(zahlen[index])-1]-zahlen[index][0]) do
und
round(xWert + i * eineLaengenEinheit), getHeight[8

Wer soll das verstehen?
Bitte benutze eine lokale Variablen und F5/F7/F8 und Strg+F5.

Ich kenne dieses Boxplots erst mal gar nicht.
Und einen Datensatz habe ich auch nicht gefunden.
Woran erkennt man, dass die Boxplots einen gleichen/unterschiedlichen Datensatz haben?

Du hattest ja geschrieben, dass es in C++ bereits funktionierte.
Gehe doch den C++ und den Delphi-Code schrittweise durch und vergleiche die Variableninhalte.

peterbelow 24. Apr 2019 12:01

AW: Seltsames Verhalten einer Funktion
 
Du rundest Gleitkommawerte auf Ganzzahlen, da kann es schon mal passieren, dass zwei Werte, die in der Dezimaldarstelllung gleich aussehen und als Nachkommateil .5 haben in der Binärdarstellung leicht unterschiedlich sind, so das einer nach oben und einer nach unten gerundet wird. Vielleicht ist das dein Problem...

freimatz 24. Apr 2019 12:14

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von Pytroxis (Beitrag 1430858)
Findet ihr einen Fehler? Langsam verzweifle ich daran und kann mir nicht erklären woran es liegen kann :/ :(

Ich kann es erklären, warum du den Fehlr nicht finden kannst SCNR.

Deine Methode ist viel zu lang und komplex. Mache mehrere kleinere daraus, z.B. trenne die Berechnung und das Malen.
Und dann wie hoika schon schrieb debugge.

Jasocul 24. Apr 2019 12:32

AW: Seltsames Verhalten einer Funktion
 
Ohne den Source im Einzelnen angesehen zu haben, habe ich folgenden Verdacht:
Es gibt globale Variablen. Die Prozeduren gehören zu keinem Objekt und es wird in den Prozeduren auf die globalen Variablen zugegriffen. Bei jedem Repaint besteht die Gefahr, dass Werte aus den globalen Variablen verwendet werden, die zum anderen "Datensatz" gehören. Die Folge ist, dass mit falschen Werten gezeichnet wird.

Pytroxis 24. Apr 2019 13:05

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von hoika (Beitrag 1430861)
Wer soll das verstehen?
Bitte benutze eine lokale Variablen und F5/F7/F8 und Strg+F5.

Das Problem was ich hierbei habe ist, dass die Variablen in einer anderen Procedure verwendet werden müssen (-> Sortieren des Datensatzes, errechnen des medians, der Quartils etc.). Danach werden sie erst zum zeichnen verwendet (in einer anderen Funktion). Demnach wüsste ich nicht wie ich auf lokale Variablen setzen soll außer vielleicht der lokale Variable den Wert der globalen zuzuweisen (-> andere Möglichkeit sehe ich gerade nicht, korrigiere mich bitte falls ich falsch liege).

Zitat:

Zitat von hoika (Beitrag 1430861)
Ich kenne dieses Boxplots erst mal gar nicht.
Und einen Datensatz habe ich auch nicht gefunden.
Woran erkennt man, dass die Boxplots einen gleichen/unterschiedlichen Datensatz haben?

Ein Boxplots ist das was du im Anhang gesehen hast (-> grafische Darstellung einer Verteilung).
Die Datensätze sind in
Delphi-Quellcode:
zahlen
gespeichert und sie werden durch den Nutzer eingeben oben in meinem Fall waren die Datensätze:
Delphi-Quellcode:
zahlen[0] := [0,1,2,3,4,5]
zahlen[1] := [0,1,2,3,4,6]
Der unterschied war hierbei die 5 bzw. 6 sprich das Maximum.
Im oberen Bild sieht man, dass beide Boxplots richtig dargestellt werden sofern die Datensätze gleich sind aber bei unterschiedlichen Datensätzen der obere Boxplot "verkrüppelt" ist.

Zitat:

Zitat von hoika (Beitrag 1430861)
Du hattest ja geschrieben, dass es in C++ bereits funktionierte.
Gehe doch den C++ und den Delphi-Code schrittweise durch und vergleiche die Variableninhalte.

Witzige Geschichte, dass kann ich nicht machen. Das ursprüngliche Programm war fertig, korrekt, als ich dann mit umschreiben auf Delphi soweit fertig war, wollte mein Lehrer, dass ich noch das vergleichen hinzufüge und dabei gibt es jetzt halt die Probleme.

Zitat:

Zitat von peterbelow (Beitrag 1430862)
Du rundest Gleitkommawerte auf Ganzzahlen, da kann es schon mal passieren, dass zwei Werte, die in der Dezimaldarstelllung gleich aussehen und als Nachkommateil .5 haben in der Binärdarstellung leicht unterschiedlich sind, so das einer nach oben und einer nach unten gerundet wird. Vielleicht ist das dein Problem...

Probeweise habe ich mal alle
Delphi-Quellcode:
round
durch
Delphi-Quellcode:
trunc
ersetz, da somit dieser Fehler ja nicht mehr auftreten dürfte.
Allerdings tritt er immer noch auf und es hat sich nichts verändert. Aber prinzipiell ist die Idee mit trunc statt round gar nicht so schlecht.


Zitat:

Zitat von freimatz (Beitrag 1430864)
Deine Methode ist viel zu lang und komplex. Mache mehrere kleinere daraus, z.B. trenne die Berechnung und das Malen.
Und dann wie hoika schon schrieb debugge.

Aber wie soll ich es denn weiter trennen? Die einzige Möglichkeit die ich sehe wären Arrays (-> Mit den Rechnungen etc.) und diesen dann an eine Funktion zum zeichnen weiterzugeben oder hast du eine bessere Idee? :D


Zitat:

Zitat von Jasocul (Beitrag 1430866)
Ohne den Source im Einzelnen angesehen zu haben, habe ich folgenden Verdacht:
Es gibt globale Variablen. Die Prozeduren gehören zu keinem Objekt und es wird in den Prozeduren auf die globalen Variablen zugegriffen. Bei jedem Repaint besteht die Gefahr, dass Werte aus den globalen Variablen verwendet werden, die zum anderen "Datensatz" gehören. Die Folge ist, dass mit falschen Werten gezeichnet wird.

Die Globalen Variablen werden eigentlich nur einmal verändert und zwar beim sortieren des Datensatzes.
In der Zeichnen Funktion werden ausschließlich lokale Variablen verwendet bzw. überschrieben, es werden nur aus den globalen Variablen gelesen, demnach dürften die globalen Variablen nicht verändert worden sein.


Ich habe die Datensätze auch mehrfach kontrolliert und getestet ob diese verändert werden o.ä. und das wurden sie nicht, daher wundert mich das ganze ja so sehr, dass die Darstellung einmal mit gleichen Datensätzen geht und das andere mal mit unterschiedlichen nicht mehr.
Werde jetzt mal debuggen und mich später nochmal melden :D

Pytroxis 24. Apr 2019 13:10

AW: Seltsames Verhalten einer Funktion
 
Ich habe jetzt noch nicht gedebuggt aber mir ist folgende aufgefallen:
Bisher waren die Datensätze immer
Delphi-Quellcode:
zahlen[0] := [1,2,3,4,5]
zahlen[1] := [1,2,3,4,6]
Dabei war dann der erste Boxplot verkrüppelt.
Nun habe ich die Datensätze einfach mal getauscht:
Delphi-Quellcode:
zahlen[0] := [1,2,3,4,6]
zahlen[1] := [1,2,3,4,5]
Und so werden beide ganz normal angezeigt.

Das wundert mich jetzt noch viel mehr

Edit:
Zitat:

Zitat von hoika (Beitrag 1430861)
Bitte benutze eine lokale Variablen und F5/F7/F8 und Strg+F5.

Das debuggen hat wirklich geholfen!
Habe meinen Fehler gefunden und jetzt fühle ich mich ziemlich dumm -_-
Habe vergessen die Variablen für Quartils und Median auch auf mehrere Boxplots auszulegen. Werde das jetzt mal ändern aber daran liegt es vermutlich.

Edit2:
Es lag tatsächlich an den Variablen, jetzt fühle ich mich wirklich dumm -_-

hoika 24. Apr 2019 14:04

AW: Seltsames Verhalten einer Funktion
 
Hallo,
geht doch.

die Quartils und Median sahen für mich eh schon etwas komisch aus,
die hatte ich auch im Verdacht ... ;)

Der Debugger ist Dein bester Freund.

Sherlock 24. Apr 2019 14:31

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von Pytroxis (Beitrag 1430871)
Edit2:
Es lag tatsächlich an den Variablen, jetzt fühle ich mich wirklich dumm -_-

Nicht dumm! Klüger als vorher ;-)

Sherlock

Pytroxis 24. Apr 2019 15:27

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von hoika (Beitrag 1430873)
Hallo,
geht doch.

die Quartils und Median sahen für mich eh schon etwas komisch aus,
die hatte ich auch im Verdacht ... ;)

Der Debugger ist Dein bester Freund.

Merk ich mir für die Zukunft :D


Zitat:

Zitat von Sherlock (Beitrag 1430876)
Nicht dumm! Klüger als vorher ;-)

Sherlock

JaJa :P


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:55 Uhr.
Seite 1 von 4  1 23     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz