Die Funktion MinutesBetween aus DateUtils rechnet merkwürdig

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Die Funktion MinutesBetween aus DateUtils rechnet merkwü

Beitrag von wp_xyz »

Mathias hat geschrieben:
Etwas wie if Now = wert then sollte man vermeiden, weil es sein kann, dass Now nie gleich wert ist.

Bei Float-Vergleichen mache ich immer ein <= oder >= .
Bei Ganzzahlen dies auch ein Vorteil sein.

Nein, bei Gleitkomma-Vergleichen darf kein "=" auftauchen. Angenommen, du führst eine Rechnung durch und willst vergleichen, ob das Ergebnis <= 3 ist. Laut Rechnung von Hand kommt exakt 3 raus. Der Vergleich "Ergebnis <= 3" wird also als "richtig" erwartet. Aber durch div. Rundungsfehler und die Disketisierung der Gleichkommazahlen erhältst du als Ergebnis am Rechner 3.0000000000000012. Nun ist "Ergebnis <= 3" falsch.

Richtig ist, immer mit SameValue zu arbeiten:

Code: Alles auswählen

function KleinerGleich(a,b: Double; Epsilon: Double): boolean;
begin
  Result := SameValue(a, b, epsilon) or (a < b);
end;

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Die Funktion MinutesBetween aus DateUtils rechnet merkwü

Beitrag von Mathias »

Aber durch div. Rundungsfehler und die Disketisierung der Gleichkommazahlen erhältst du als Ergebnis am Rechner 3.0000000000000012. Nun ist "Ergebnis <= 3" falsch.
Da hat der PC vollkommen recht, 3.0000000000000012 ist natürlich grösser als 3.0 .

Eines ist sicher, niemals einen Float mit = vergleichen, ausser es ist 0.

Code: Alles auswählen

var
  i: integer;
begin
  i := 0;
  repeat
    Inc(i);
  until i >= 10;
end;

Ich wollte nur sagen, das dies mir sympatischer ist, als nur ein = .
Wen das i mit einem Timer oder sonst etwas speziellen inkrementiert wird, kann es mal passieren, das i auf einmal 2 höher als nur 1 ist.
Das kann dann sehr lange Fehlersuchungen geben.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: Die Funktion MinutesBetween aus DateUtils rechnet merkwü

Beitrag von Timm Thaler »

wp_xyz hat geschrieben:Nein, bei Gleitkomma-Vergleichen darf kein "=" auftauchen.


Naja der Witz im vorliegenden Fall ist ja, dass man erstmal wissen muss, dass DateTime ein Float benutzt. Mir war das lange nicht klar, ich dachte das ist ein record mit mehreren int Speicherstellen für sec, min, hour, day...

Andere Sprachen nehmen dafür longint. Aber Float für eine diskrete Zeitdarstellung ist ja wirklich mal eine saublöde Idee... :shock: Zumal float ja auch noch abhängig von der Rechnerarchitektur unterschiedliche Genaugigkeit hat.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Die Funktion MinutesBetween aus DateUtils rechnet merkwü

Beitrag von wp_xyz »

Naja...

Die heutige Implementierung im FPC lehnt sich an Delphi an, das es aber schon gab, als 64-Bit Integer in weiter Ferne waren. Und mit den 32-Bit der Unix-Welt, die die Zeit in Sekunden seit dem 1.1.1970 zählt, erwartet uns in 20 Jahren das nächste "Jahr-2000-Problem", wenn dieser Zähler überlauft (https://de.wikipedia.org/wiki/Jahr-2038-Problem). Zu der 16-Bit Zeit, als Delphi 1 das Licht der Welt erblickte, war die Zeit-Darstellung als Float daher naheliegend und sehr elegant im Vergleich zu monströsen Jahr-Monat-Tag-Stunde-Minute-Sekunden-Millisekunden-Records.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: Die Funktion MinutesBetween aus DateUtils rechnet merkwü

Beitrag von Timm Thaler »

wp_xyz hat geschrieben:Zu der 16-Bit Zeit, als Delphi 1 das Licht der Welt erblickte, war die Zeit-Darstellung als Float daher naheliegend und sehr elegant im Vergleich zu monströsen Jahr-Monat-Tag-Stunde-Minute-Sekunden-Millisekunden-Records.


Zur 16bit Zeit war aber auch ein float schon reichlich ungenau. Ich weiss nicht mehr, was bei Turbo Pascal das gängige Datumsformat war, aber für die Astroprogramme wurden Datentypen selbst gebastelt, weil die Genauigkeit bei weitem nicht ausreichte.

Ein yy-mm-dd hh:mm:ss "Record" mit 2xBCD Codierung verwende ich regelmässig auf Mikrocontrollern, weil man damit wunderbar sowohl im Grossen als auch im Kleinen rechnen und vergleichen kann, daran ist nichts monströs. Und ich decke damit alles bis 2099 mit 1sec Auflösung ab, wenn meine Elektronik solange läuft bin ich zufrieden. ;-)

Welche Auflösung bekommt man den mit einem single oder double Datumstyp hin, wenn er das aktuelle Datum enthalten soll? Ich kann das grad nicht testen, hab hier kein Lazarus.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Die Funktion MinutesBetween aus DateUtils rechnet merkwü

Beitrag von wp_xyz »

Timm Thaler hat geschrieben:Welche Auflösung bekommt man den mit einem single oder double Datumstyp hin, wenn er das aktuelle Datum enthalten soll? Ich kann das grad nicht testen, hab hier kein Lazarus.

Lass mich mal rechnen:

  • Double hat 15 Dezimalstellen. Im Jahr 2100 sind 200 Jahre, also etwa 73000 Tage seit dem Datumsursprung vergangen, sagen wir 10^5. Damit bleiben von den 15 Stellen nach 10 Stellen übrig. 1 Tag hat 24*60*60 = 86400 Sekunden, also etwa 10^5 Sekunden. Damit bleiben noch 5 Dezimalstellen für die Auflösung pro Sekunde, die kleinste Auflösung wäre dann 10 µs.
  • Single hat nur 7 Stellen, das heißt, man könnte eine Sekunde auf 2 Dezimalstellen auflösen (10 ms).
  • Bei Extended dagegen würden die 19 Dezimalstellen eine 10^4 mal feinere Auflösung ermöglich als bei Double, also 1 ns.
Zum aktuellen Datum ist kein größer Unterschied: 42919 Tage gegenüber 73000 ist knapp ein Faktor 2.

Antworten