Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Float in zwei Integer zerlegen (https://www.delphipraxis.net/185560-float-zwei-integer-zerlegen.html)

Shark99 20. Jun 2015 08:42

AW: Float in zwei Integer zerlegen
 
Ja ich merke gerade Indexierung nach TDateTime war keine gute Idee. Ich kann so zwar einen bestimmten Tag blitzartig finden (der Array ist sortiert), aber abspeichern des TDateTime in einen JSON mit FloatToStr() und das Parsen um es zu laden führt zur Verfälschung der Daten (zwar Unterhalb einer Sekunde, aber ich finde damit die Duplikate nicht mehr 100% zuverlässig). Vielleicht sollte ich Unixtime oder Filetime nehmen.

Popov 20. Jun 2015 10:18

AW: Float in zwei Integer zerlegen
 
Zitat:

Zitat von Shark99 (Beitrag 1305855)
Irgendwas ist faul. Aus einem TDateTime von 42173,681694 wird durch Trunc(Frac(DateTime) * 24 * 60 * 60 * 1000) ein Integer von 58898345. Werde es wohl doch in einen String speichern müssen damit ich es wieder finde.

Bezeichne bitte nicht etwas als faul was nicht faul ist. Alles ist so wie es sein soll. Aber seit Menschengedenken weiß man, dass man Fließkommawerte nicht miteinander vergleicht, bzw. es dabei zu Problemen kommen kann. Was glaubst du bedeutet das Wort: Fließkomma?

Ich hab schon zig Projekte geschrieben in deinen ich Daten miteinander verglichen oder gesucht habe. Das klappt schon, man muss sich nur der Problematik bewußt sein.

Zitat:

Zitat von Shark99 (Beitrag 1305855)
Eben, es gibt Rundungsfehler und ich finde den Record nicht wieder.

Wenn du das Datum und Uhrzeit in zwei Integer zerlegst, warum machst du dann wieder ein Double daraus um es zu vergleichen. Warum machst du den Double mit dem du suchst nicht zu zwei Integern? Und schon ist das Problem beseitigt. Und sollte es nötig sein mit Double-Werten zu vergleichen, wie wäre es den Double zuerst zu zerlegen und dann wieder zum Double zu machen. Dann haben beide Double-Werte, der gespeicherte und der mit dem du vergleichst, die gleiche Rundungs-Ungenauigkeiten.

Dejan Vu 20. Jun 2015 11:56

AW: Float in zwei Integer zerlegen
 
Wer Fließkommazahlen auf exakte Gleichheit vergleicht, wird geteert und gefedert. Wie oft denn noch?

Stevie 20. Jun 2015 12:56

AW: Float in zwei Integer zerlegen
 
Zitat:

Zitat von Dejan Vu (Beitrag 1305876)
Wer Fließkommazahlen auf exakte Gleichheit vergleicht, wird geteert und gefedert. Wie oft denn noch?

Blödsinn, ein Float kann sehr wohl als Index benutzt werden. Man darf nur nicht weiter rechnen damit oder ihn zerlegen und wieder zusammenfügen!

Medium 20. Jun 2015 13:19

AW: Float in zwei Integer zerlegen
 
Also wenn die Zeit als Index dient und vor allem mit anderen Zeitwerten verglichen werden soll, ist ein TDateTime (=Double) so ziemlich die schlechtest mögliche Struktur die man wählen könnte. Die Gründe werden hier fast wöchentlich durchgekaut. Nimm einfach statt eines TDateTimes eien Cardinal, hau das Datum als Unix-Timestamp da rein, und fertig ist die Laube. Passt sogar in TListItem.Data. Ab 2038 wird man vermutlich aber mal einen Wartungslauf machen müssen, oder man nimmt einen Int64 und hat ein paar Jahrtausende Ruhe (muss dann aber auch wieder Pointer im ListItem hinterlegen).
Aber mit dem Float wirst du dir irgendwann gewaltig den Rücken brechen hier.

hathor 20. Jun 2015 14:43

AW: Float in zwei Integer zerlegen
 
Zitat:

Zitat von Shark99 (Beitrag 1305802)
Ich möchte eine Gleitzahl in zwei Integer zerlegen.

Vorkomma und Nachkomma sollen jeweils zwei Integer bilden. Später will ich das ganze zusammensetzen.

Lösungen wurden schon gezeigt - hier eine Zusammenfassung:

Delphi-Quellcode:
procedure MM(s:string); begin Form1.Memo1.Lines.Add(s); end;

Function LDOUBLE(d:Double):INTEGER;
begin
  Result:= TRUNC(d);
//evtl. Zahl verschlüsseln
end;

Function RDOUBLE(d:Double):INTEGER;
begin
  Result:= TRUNC(FRAC(d) * 24 * 60 * 60 * 1000);
//evtl. Zahl verschlüsseln
end;

Function INTINTDOUBLE(a, b : INTEGER): DOUBLE;
begin
// evtl. Zahlen a und b vorher entschlüsseln
  Result:= a + (b / 24 / 60 / 60 / 1000);
end;

procedure TForm1.Button6Click(Sender: TObject);
var a, b : INTEGER;
begin
MM(DATETIMETOSTR(now));

a:= LDOUBLE(now);
b:= RDOUBLE(now);
MM('LDOUBLE: '+INTTOSTR(a));
MM('RDOUBLE: '+INTTOSTR(b));

MM('Date: '+DATETOSTR(INTINTDOUBLE(a,b)));
MM('Time: '+TIMETOSTR(INTINTDOUBLE(a,b)));
MM('ReCombined: '+DATETIMETOSTR(INTINTDOUBLE(a,b)));
end;

BadenPower 20. Jun 2015 15:48

AW: Float in zwei Integer zerlegen
 
Zitat:

Zitat von hathor (Beitrag 1305897)
Lösungen wurden schon gezeigt - hier eine Zusammenfassung:

Wenn dann doch schon so:
Delphi-Quellcode:
procedure MM(s:string; AMemo: TMemo); begin AMemo.Lines.Add(s); end;

function LDOUBLE(d:Double):INTEGER;
begin
  Result := TRUNC(d);
end;

function RDOUBLE(d:Double):INTEGER;
begin
  Result := TRUNC(FRAC(d) * 24 * 60 * 60 * 1000);
end;

function INTINTDOUBLE(a, b : INTEGER): DOUBLE;
begin
  Result := a + (b / 24 / 60 / 60 / 1000);
end;

procedure TForm1.Button6Click(Sender: TObject);
var a, b : INTEGER;
begin
  MM(DATETIMETOSTR(now),Self.Memo1);

  a := LDOUBLE(now);
  b := RDOUBLE(now);
  MM('LDOUBLE: '+INTTOSTR(a),Self.Memo1);
  MM('RDOUBLE: '+INTTOSTR(b),Self.Memo1);

  MM('Date: '+DATETOSTR(INTINTDOUBLE(a,b)),Self.Memo1);
  MM('Time: '+TIMETOSTR(INTINTDOUBLE(a,b)),Self.Memo1);
  MM('ReCombined: '+DATETIMETOSTR(INTINTDOUBLE(a,b)),Self.Memo1);
end;
Wir wollen ja keine Instanzen der Form verärgern.

Popov 20. Jun 2015 16:05

AW: Float in zwei Integer zerlegen
 
Oder du benutzt:

Delphi-Quellcode:
function DateTimeToFileDate(DateTime: TDateTime): Integer;
//Delphi Datum (Double) in Betriebsystem Zeitstempel (Integer)
um Delphi-Datum in ein Integer zu konvertieren.

Zurück geht es so:

Delphi-Quellcode:
function FileDateToDateTime(FileDate: Integer): TDateTime;
//Betriebsystem Zeitstempel (Integer) in Delphi Datum (Double)
Einschränkungen:
Der Zeitstempel fängt 01.01.1980 an, Delphi-Datum dagegen 01.01.1900. Die Funktionen berücksichtigen das, so dass man nichts selbst dazurechnen oder abziehen muss, aber es sind keine Daten möglich die kleiner 1980 sind.

Weitere Einschränkungen: es werden keine Millisekunden gesichert. Und zuallerletzt, ich habe das Gefühl, dass irgendwer hier pfuscht und nicht jede Sekunde gespeichert wird, sondern jede zweite Sekunde. Vielleicht weil man so ein Bit spart.

Dejan Vu 20. Jun 2015 16:44

AW: Float in zwei Integer zerlegen
 
Zitat:

Zitat von Stevie (Beitrag 1305882)
Zitat:

Zitat von Dejan Vu (Beitrag 1305876)
Wer Fließkommazahlen auf exakte Gleichheit vergleicht, wird geteert und gefedert. Wie oft denn noch?

Blödsinn, ein Float kann sehr wohl als Index benutzt werden. Man darf nur nicht weiter rechnen damit oder ihn zerlegen und wieder zusammenfügen!

Und das ist dann auch Blödsinn. Natürlich darf man rechnen, zerlegen und wieder zusammenfügen. Nur e-x-a-k-t v-e-r-g-l-e-i-c-h-e-n nicht. Aber Dir muss ich das ja nicht erklären, sondern höchstens um Formulierungen ringen.
:P

Stevie 20. Jun 2015 19:45

AW: Float in zwei Integer zerlegen
 
Zitat:

Zitat von Dejan Vu (Beitrag 1305904)
Zitat:

Zitat von Stevie (Beitrag 1305882)
Zitat:

Zitat von Dejan Vu (Beitrag 1305876)
Wer Fließkommazahlen auf exakte Gleichheit vergleicht, wird geteert und gefedert. Wie oft denn noch?

Blödsinn, ein Float kann sehr wohl als Index benutzt werden. Man darf nur nicht weiter rechnen damit oder ihn zerlegen und wieder zusammenfügen!

Und das ist dann auch Blödsinn. Natürlich darf man rechnen, zerlegen und wieder zusammenfügen. Nur e-x-a-k-t v-e-r-g-l-e-i-c-h-e-n nicht. Aber Dir muss ich das ja nicht erklären, sondern höchstens um Formulierungen ringen.
:P

Irgendwie bezweifle ich den Nutzen eines Indexes, den man nur beinahe vergleichen kann.

Popov 20. Jun 2015 20:09

AW: Float in zwei Integer zerlegen
 
Zitat:

Zitat von Stevie (Beitrag 1305914)
Irgendwie bezweifle ich den Nutzen eines Indexes, den man nur beinahe vergleichen kann.

Gibt es, nennt sich SVerweis in Excel und hat eine Option mit der man einstellen kann ob das Suchkriterium genau sein muss oder nur in der Nähe.

mkinzler 20. Jun 2015 20:37

AW: Float in zwei Integer zerlegen
 
Als Index aber alles andere als optimal

BUG 20. Jun 2015 20:55

AW: Float in zwei Integer zerlegen
 
Zitat:

Zitat von mkinzler (Beitrag 1305921)
Als Index aber alles andere als optimal

Wenn man nicht gerade einen Hash-basierte Index hat, kann man auch Bereichsabfragen (Wert +/- Epsilon) beschleunigen.

Ansonsten hat sich die Diskussion imho etwas festgelaufen. Eine Lösung für das konkrete Problem (siehe Titel) wurde ja schon genannt und für das eigentliche Problem (die Performance) fehlen Informationen zu den Daten und der Anwendung.

p80286 21. Jun 2015 10:28

AW: Float in zwei Integer zerlegen
 
Wenn Du nicht vor hast mit den Daten irgendeine Operation durchzuführen, mach's über einen Typecast
Delphi-Quellcode:
type
  TTrenner=packed record t1,t2=integer; end;


...
x.DTpart1:=ttrenner(MyValue).t1;
x.DTpart2:=ttrenner(MyValue).t2;
...
Nur habe ich so meine Zweifel, daß das gut geht.

Gruß
K-H

Dejan Vu 21. Jun 2015 11:37

AW: Float in zwei Integer zerlegen
 
Mal zurück zum Thema bzw. dem eigentlichen 'Sinn' der Frage.
1. Eine Liste mit +100k Werten enthält einen TDateTime-Wert.
2. Der Wert soll als Index bzw. Suchbegriff herhalten.
3. Beim speichern und wieder laden als JSON wird der TDateTime auf +/- 1 Sekunde gerundet.

Wg. (3) würde ich dann
a: JSON durch ein anderes Format ersetzen
b: JSON Beibehalten, aber den Suchbegriff ändern

Sagen wir mal, wir wollen JSON beibehalten. Dann könnte eine Lösung so aussehen: Jeder Record hat zusätzlich noch einen Wert 'ID', der erstens 4 Bytes lang ist und zweitens aus dem TDateTime gebildet werden kann. Dieser Wert muss ja nicht mit abgespeichert werden, solange er den +/- 1 Sekunde Fehler kompensieren kann. Ansonsten wird er eben mit abgespeichert.

Oder wir sagen uns: "Blöd, JSON taugt hier eben nicht". Dann können wir die Daten trotzdem sehr einfach ablegen, denn ich kann so einen Record 1:1 (mit Einschränkungen, also kein 'String', sondern nur 'String[X]' etc.) direkt in einen Stream kopieren. Oder ich schreibe mir meinen Reader/Writer für so ein Record mal eben selbst.

Dalai 21. Jun 2015 12:45

AW: Float in zwei Integer zerlegen
 
Es gibt noch eine andere Möglichkeit, auch wenn ich die Tauglichkeit mal offen lasse: TListItem ableiten und mit einem zusätzlichen TDateTime-Attribut ausstatten und die entstehende Klasse statt der TListItems benutzen.

MfG Dalai

Dejan Vu 21. Jun 2015 13:03

AW: Float in zwei Integer zerlegen
 
Oh natürlich, es gibt viele Wege, dieses Dilemma zu lösen. Ich wollte nur versuchen, die Erkenntnisse zusammenzufassen und dem Thread wieder eine Richtung zu geben.

Popov 21. Jun 2015 14:11

AW: Float in zwei Integer zerlegen
 
Um ehrlich zu sein verstehe ich immer noch nicht das Problem des TE. Ich sortiere seit Jahren Listen, auch mit Daten und Zeiten, und hab keine Probleme. Das Problem ist weniger TDateTime als der Glaube es irgendwie machen zu müssen.

Hier ein Beispiel mit 10k Daten (also 100.000). Es werden Daten zufällig erzeugt und dann sortiert. Um diese Menge zu sortieren benötigt mein sechs Jahre alte Rechner 120 ms. Wo ist also das Problem?

Delphi-Quellcode:
uses
  Contnrs, DateUtils;

type
  TTest = class
    DateTime: TDateTime;
  end;

var
  ol: TObjectList;

procedure TForm1.Button1Click(Sender: TObject);
const
  MsMax = 24 * 60 * 60 * 1000;
var
  t: TTime;
  i: Integer;
  Test: TTest;

  function CompareDT(Item1, Item2: Pointer): Integer;
  begin
    Result := CompareDateTime(TTest(Item1).DateTime, TTest(Item2).DateTime);
  end;

begin
  t := Now;

  ol.Clear;
  for i := 1 to 100000 do //10k Daten erzeugen
  begin
    Test := TTest.Create;
    Test.DateTime := Random(Trunc(Now)) + (Random(MsMax) / MsMax); //Zufälliges TDateTime
    ol.Add(Test);
  end;

  ol.Sort(@CompareDT);

  with ListView1 do
  begin
    OwnerData := True;
    ViewStyle := vsReport; //1 Column erstellen, breite 150 Pixel
    OwnerData := True;
    Items.Count := ol.Count;
  end;

  ShowMessage('Dauer: ' + IntToStr(MilliSecondsBetween(t, Now)) + 'ms');
end;

procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
var
  Test: TTest;
begin
  Test := TTest(ol.Items[Item.Index]);
  Item.Caption := FormatDateTime('dd.MM.yyyy hh:nn:ss', Test.DateTime);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ol := TObjectList.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ol.Free;
end;

Dejan Vu 21. Jun 2015 16:57

AW: Float in zwei Integer zerlegen
 
10k sind 10.000 aber ansonsten hast Du Recht.

Popov 21. Jun 2015 22:57

AW: Float in zwei Integer zerlegen
 
Yep, und gleich zwei mal den Fehler gemacht. In dem Fall werden die 10.000 Daten in 15 ms sortiert.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:32 Uhr.
Seite 2 von 2     12   

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