AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Vergleich von Zahlen

Ein Thema von Beach · begonnen am 3. Mär 2020 · letzter Beitrag vom 6. Mär 2020
Antwort Antwort
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#1

AW: Vergleich von Zahlen

  Alt 3. Mär 2020, 16:41
Zitat:
so in der Art:
Dann aber bitte nicht so ein Käse
if error = TRUE then
  Mit Zitat antworten Zitat
Beach

Registriert seit: 3. Mär 2019
Ort: Kappel
46 Beiträge
 
FreePascal / Lazarus
 
#2

AW: Vergleich von Zahlen

  Alt 3. Mär 2020, 17:10
Das war QD
Außerdem bin ihc jemand der nur ab und zu aus Spaß sowas macht und dann immer offen ist, wenn er ERklärt bekommt was er falsch macht oder was man ordentlicher "sauberer" lösen kann.

Aber ich vermute das du auf
Code:
IF error then
anspielst? Da so eh der Vergleich auf TRUE gemacht wird?

So grob funktioniert das jetzt sogar. Allerdings scheint meine Funktion, die mit den String mit Dezimalpunkt in ein Float umwandelt (hier im Forum gefunden) die Nachkommastellen abzuschneiden.
Oder Ich runde irgendwo wo ich es im Moment nicht sehe. Habe ich "glatte" Zahlen (ohne Nachkommastelle) bekomme ich das passende Ergebnis.
Habe ich, als Beispiel Nachkomma stellen (Der Intervall ist immer 100,1, also wäre es richtig)
dann bekomme ich gesagt das mein Ergenis -1 (also ungültig) ist

Zitat:
Targets :
0.000000 100.100000 200.200000 300.300000 400.400000
Meine Funktionen

MyStrToFloat() hier im Forum gefunden.
Code:
 function MyStrToFloat(AString: string): double;
begin
  AString := StringReplace(AString, '.', DecimalSeparator, [rfIgnoreCase, rfReplaceAll]);
  AString := StringReplace(AString, ',', DecimalSeparator, [rfIgnoreCase, rfReplaceAll]);
  result := StrToFloat(AString);
end;
Meine eigene Funktion:
In Targets übergebe ich das Stringarray mit den einzelnen Werten.
Rückgeliefert werden soll der Intervall
in Values.TargetCount ist die Anzahl der vorhandenen Targets.

Code:
function CalculateStep(Targets: array of string): double;
  //Größe der Schrittweite, -1 wenn ungueltig
var
  i, j: integer;
  m, r: double;
  l: boolean;

begin
  i := 0;
  j := 0;
  r := 0;
  l := False;

  i := Values.TargetCount;
  m := MyStrToFloat(Targets[1]) - MyStrToFloat(Targets[0]);

  for j := 1 to i - 1 do
  begin
    if MyStrToFloat(Targets[j]) - MyStrToFloat(Targets[j - 1]) = m then
      l := True
    else
      l := False;
  end;

  if l then
    r := m
  else
    r := -1;

  Form1.Edit1.Text := FloatToStr(m);
  Form1.Edit2.Text := FloatToStr(r);
  Form1.Memo1.Text := ArrayToStr(Targets);

end;
MfG Jürgen
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.340 Beiträge
 
Delphi 12 Athens
 
#3

AW: Vergleich von Zahlen

  Alt 3. Mär 2020, 17:19
Aber ich vermute das du auf
Code:
IF error then
anspielst? Da so eh der Vergleich auf TRUE gemacht wird?
Im Prinzip ja, aber

Boolean ist 1 Byte groß und kennt somit 256 verschiedene Werte.
Die Konstanten True und False sind jeweils als ein Wert definiert (0 oder 1 und z.B. im C++ auch gern als -1 statt 1)
1 = ein Bit aktiv
-1 = alle Bits aktiv

Die Auswertung eines BOOLs sieht aber anders aus
ist 0 = False
nicht 0 = True

Tja, und nun kann es vorkommen, dass du von irgendwo ein "anderes" True bekommst und somit dein =True nicht mehr trifft.
Delphi-Quellcode:
var
  B: Boolean;
begin
  //B := False;
  //B := True;
  B := Boolean(2);

  if B then
    ShowMessage('1: True');
  if not B then
    ShowMessage('1: False');

  if B = True then
    ShowMessage('2: True');
  if B = False then
    ShowMessage('2: False');
  if B <> False then
    ShowMessage('3: True');


Zitat:
So grob funktioniert das jetzt sogar. Allerdings scheint meine Funktion, die mit den String mit Dezimalpunkt in ein Float umwandelt (hier im Forum gefunden) die Nachkommastellen abzuschneiden.
Was kommt wohl raus, wenn der String mal Beides drin hat?
z.B. 123.456,78
Dann knallt es.

StrToFloat hat einen Parameter FormatSettings, den sollte man verwenden, wenn man ein bestimmtes Format haben möchte, welches nicht unbedingt der aktuellen Systemsprache entspricht.


Zitat:
Delphi-Quellcode:
  for j := 1 to i - 1 do
  begin
    if MyStrToFloat(Targets[j]) - MyStrToFloat(Targets[j - 1]) = m then
      l := True
    else
      l := False;
  end;
Wenn ich hier mal den "unnötigen" Teil entferne, wem fällt da auf, was in der Schleife schief laufen kann?
Delphi-Quellcode:
  for j := 1 to i - 1 do
  begin
    l := MyStrToFloat(Targets[j]) - MyStrToFloat(Targets[j - 1]) = m;
  end;
Delphi-Quellcode:
  if i > 2 then // if i - 1 > 1 then
    l := MyStrToFloat(Targets[i - 1]) - MyStrToFloat(Targets[i - 2]) = m;

Genau, alle nachfolgenden Durchläufe überschreiben diese Variable und somit wird nur das Letzte ausgewertet.

Bei z.B. 0.000000 100.000000 123456789.012 -666 300.000000 400.000000
also 0.000000 100.000000 ... irgendwas ... 300.000000 400.000000 (2 vorn und 2 hinten gleich weit entfernt)
schlägt deine Prüfschleife fehl.

Ich vermute das else l := False; ist so nicht gewollt und wenn es dann eh schon TRUE ist, dann kann es nicht noch TRUEr werden, also könnte man beim ersten True die Schleife abbrechen (Break).


Da Fließkommazahlen Rundungafehler enthalten können, aufgrund der binären Speicherung von dezimalen Zahlen und der gegrenzten Anzahl von Bits,
Vergleiche immer nur mit IsZero, Delphi-Referenz durchsuchenSameValue, CompareValue und Dergleichen, mit einem "angemessenen" Delta.
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 3. Mär 2020 um 18:18 Uhr)
  Mit Zitat antworten Zitat
Beach

Registriert seit: 3. Mär 2019
Ort: Kappel
46 Beiträge
 
FreePascal / Lazarus
 
#4

AW: Vergleich von Zahlen

  Alt 3. Mär 2020, 20:54
Wow. Viel Input...
Danke euch dafür.

[...]
Die Auswertung eines BOOLs sieht aber anders aus
ist 0 = False
nicht 0 = True

Tja, und nun kann es vorkommen, dass du von irgendwo ein "anderes" True bekommst und somit dein =True nicht mehr trifft.
[....]
Da mus ich mich nochmal in Ruhe mit auseinander setzen. Hab es zwar, glaube ich, Oberflächlich verstanden, aber werde da mal dein Beispiel testen um es auch wirklich zu verstehen.

Zitat:
[...]Was kommt wohl raus, wenn der String mal Beides drin hat?
z.B. 123.456,78
Dann knallt es.[...]
Womit du prinzipiell Recht hast, aber da ich hier ein fest vorgegebenes Format habe das nicht variabel ist, wird es in diesem speziellen Fall nicht vorkommen. Daher habe ich mich für diese Variante entschieden.
Zitat:
StrToFloat hat einen Parameter FormatSettings, den sollte man verwenden, wenn man ein bestimmtes Format haben möchte, welches nicht unbedingt der aktuellen Systemsprache entspricht.
Das erinnert mich an mein Buch. Sollte ich nochmal rauskramen. Dort ging es auch um das Problem mit dem Rundungsfehler.
Hatte ich aus den Augen verloren und muss ich mich nochmals mit beschäftigen.

Zitat:
[...]
Delphi-Quellcode:
  if i > 2 then // if i - 1 > 1 then
    l := MyStrToFloat(Targets[i - 1]) - MyStrToFloat(Targets[i - 2]) = m;

Genau, alle nachfolgenden Durchläufe überschreiben diese Variable und somit wird nur das Letzte ausgewertet.

Bei z.B. 0.000000 100.000000 123456789.012 -666 300.000000 400.000000
also 0.000000 100.000000 ... irgendwas ... 300.000000 400.000000 (2 vorn und 2 hinten gleich weit entfernt)
schlägt deine Prüfschleife fehl.
[..]
Das bringt mich, glaub ich auf den richtigen Weg meinen Fehler zu finden.
Wenn der Vergleich das erstemal UNWAHR ist muss ich abbrechen weil dann ja eigentlich die Bedingung, alle Werte im gleichen Intervall, bereits UNWAHR ist und ich auch gar nicht mehr weiter prüfen brauch.

[...]Was denn nun?
Haben die Daten 6 Nachkommastellen oder können sie auch Nachkommastellen enthalten.
Wieder mal unpräzise von mir ausgedrückt. Sorry.
Ich versuche es konkreter:

Das Format mit den 6 Nachkommastellen steht so fest. Die Werte werden meistens aber nur ganzzahlig sein. Also mit 6x 0 hinter dem Dezimalpunkt. Beispiel: 100.000000

Es könnte aber auch sein das ich keine ganzzahligen Werte habe. Als Beispiel 100,5 was dann als 100.500000 in den Daten dargestellt wird.
Daher muss ich wohl mit Fließkommazahlen arbeiten.
MfG Jürgen
  Mit Zitat antworten Zitat
Beach

Registriert seit: 3. Mär 2019
Ort: Kappel
46 Beiträge
 
FreePascal / Lazarus
 
#5

AW: Vergleich von Zahlen

  Alt 4. Mär 2020, 09:04
Hab eine andere Funktion im Lazarus Forum gefunden, welche sicherer funktioniert.
Allerdings müsste, um vollständig zu sein, noch 2 Varianten (DezTrenner ',' TausenderTrenner '.' und umgekehrt) zusätzlich behandelt werden.
Code:
function MyStrToFloat(AString: string): double;
var
  x: Double;
  fs: TFormatSettings;
begin
  x := NaN;
  fs := FormatSettings;
  fs.DecimalSeparator := ',';
  fs.ThousandSeparator := ',';
  if not TryStrToFloat(AString, x, fs) then begin
    fs := FormatSettings;
    fs.DecimalSeparator := '.';
    fs.ThousandSeparator := '.';
    if not TryStrToFloat(AString, x, fs) then
      x := NaN;
  end;
  if IsNaN(x) then
    Result := 0
  else
    Result := x;

end;
Meine CalculateStep() habe ich auch nochmals überarbeitet.
Soweit ich das bis jetzt getestet habe, funktioniert das alles auch wie gewünscht.
Es ergibt sihc für mich allerdings noch eine Frage:
Wenn ich den Wert von i prüfe (mehr als 2 Werte, genau 2 Werte, wseniger als 2 Werte) Prüft man mit einzelnen IF Statements und bricht die Funktion ab oder schachtelt man die IFs besser? Oder würde man evtl sogar auf CASE ausweichen?

Außerdem nutze ich eine Extra variable um einen Zwischenwert zu berechnen (Variable n) Da ich es so übersichtlicher finde.
Oder wäre es besser die Berechnung direkt in der Funktion sameValue() anzugeben?

Code:
function CalculateStep(Targets: array of string): double;
  //Größe der Schrittweite, NaN wenn ungueltig ( wird dann mit IsNaN() geprüft )
var
  i, j: integer;
  m, n: double;

begin

  i := Values.TargetCount;             // Anzahl der Targets aus dem File
  m := MyStrToFloat(Targets[1]) - MyStrToFloat(Targets[0]); // 1. Step

  if i < 2 then
  begin               // Sollte nur ein Wert vorhanden sein,
    Result := NaN;    // liefert die Funktion ungültig zurück
    exit;
  end;

  if i < 3 then       // Wenn es weniger als 3 Werte gibt
  begin               // Dann ist der Intervall in Ordnung
    Result := m;      // Es wird der 1.Step zurückgeliefert
    exit;
  end;

  for j := 2 to i - 1 do  // 3 Werte oder mehr, prüfen auf gültigen Intervall
  begin
    n := MyStrToFloat(Targets[j]) - MyStrToFloat(Targets[j - 1]);
    if not sameValue(n, m, 0) then
    begin
      m := NaN;           // Wenn ein Intervall ungültig ist, Abbrechen und
      break;              // Ungültig zurückliefern
    end;

  end;

  Result := m;            // Alle Intervall OK, also Wert zurückgeben
end;
Allen ein Danke die sich die Mühe machen und gemacht haben etwas Licht in mein Programmierdunkel zu bringen.
MfG Jürgen
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.340 Beiträge
 
Delphi 12 Athens
 
#6

AW: Vergleich von Zahlen

  Alt 4. Mär 2020, 12:18
Zitat:
Delphi-Quellcode:
fs.DecimalSeparator := ',';
fs.ThousandSeparator := ',';

...

fs.DecimalSeparator := '.';
fs.ThousandSeparator := '.';
Beide Zeichen gleich, das kann nicht funktionieren.

Da sich sowas nicht ändert und man das öfters gebraucht...
Delphi-Quellcode:
// global bzw. zentral
var
  FSUS, FSDE: TFormatSettings;

// Init
  {
  FSUS := FormatSettings;
  FSUS.DecimalSeparator := '.';
  FSUS.ThousandSeparator := ',';
  FSDE := FormatSettings;
  FSDE.DecimalSeparator := ',';
  FSDE.ThousandSeparator := '.';
  }

  FSUS := TFormatSettings.Create('en-US'); // oder TFormatSettings.Create($0409);
  FSDE := TFormatSettings.Create('de-DE'); // oder TFormatSettings.Create($0407);
Dann fliegt erstmal die ständige Definition raus
Delphi-Quellcode:
function MyStrToFloat(const AString: string): double;
var
  x: Double;
begin
  x := NaN;
  if not TryStrToFloat(AString, x, FSUS) then begin
    if not TryStrToFloat(AString, x, FSDE) then
      x := NaN;
  end;
  if IsNaN(x) then
    Result := 0
  else
    Result := x;
end;
und wenn man weiter Unnötiges entfernt, dann bleibt nicht mehr viel übrig
Delphi-Quellcode:
function MyStrToFloat(const AString: string): double;
begin
  if not TryStrToFloat(AString, Result, FSUS) and not TryStrToFloat(AString, Result, FSDE) then
    Result := 0;
end;
oder
Delphi-Quellcode:
function MyStrToFloat(const AString: string): double;
begin
  if not TryStrToFloat(AString, Result, FSUS) then
    Result := StrToFloatDef(AString, 0, FSDE);
end;
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 4. Mär 2020 um 20:33 Uhr)
  Mit Zitat antworten Zitat
Beach

Registriert seit: 3. Mär 2019
Ort: Kappel
46 Beiträge
 
FreePascal / Lazarus
 
#7

AW: Vergleich von Zahlen

  Alt 6. Mär 2020, 07:01
Interessant wie weit man das verkürzen kann.

Danke für die Tipps
MfG Jürgen
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:49 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz