Entwickler-Ecke
Windows API - GetTickCount: Braucht man überhaupt eine Bereichsprüfung?
rushifell - Mo 26.11.12 18:46
Titel: GetTickCount: Braucht man überhaupt eine Bereichsprüfung?
Hallo,
ich habe eine Frage zu GetTickCount. Ich habe mal im Internet gelesen, man bräuchte bei GetTickCount eine Bereichsprüfung, da der Wert die Anzahl der Millisekunden seit dem Systemstart zurückgibt und der Bereich nach etwa 50 Tagen überschritten wird. GetTickCount liefert einen Uint32-Wert zurück, also eine Variable vom Typ Cardinal.
Was passiert, wenn der höchste Wert, also 4294967295 überschritten wird? Die Zählung beginnt von vorne!? Nun habe ich folgendes ausprobiert:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TForm1.Button1Click(Sender: TObject); Var c1, c2:cardinal; begin c1:=4294967295; c2:=10; ShowMessage(InttoStr(c2-c1)); end; |
Der Wert 11 wird (schätze ich mal) zurückgeliefert, da die Zählung bei 0 beginnt (0..10 sind 11 Ziffern). Es wird also, wie ich erwartet hätte, ein negativer Wert zurückgeliefert. Die Differenz stimmt bis aus die kleine Abweichung von einer Millisekunde.
Nun habe ich für die Zeitmessung folgenden Code geschrieben. Leider kann ich es aus Zeitgründen nicht testen ;-) Aber eigentlich müsste das doch funktionieren. Oder habe ich etwas übersehen?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| type
TClock=record OldTick,NewTick, MilliSeconds, TimeElapsed:Cardinal; end; ... implementation Var Clock:TClock; ... procedure TForm1.Button2Click(Sender: TObject); begin Clock.OldTick:=GetTickCount; Clock.TimeElapsed:=0; Timer1.Enabled:=True; end;
procedure TForm1.Timer1Timer(Sender: TObject); begin Clock.NewTick:=GetTickCount;
Clock.Milliseconds:=Clock.NewTick-Clock.OldTick; Clock.TimeElapsed:=Clock.TimeElapsed+Clock.MilliSeconds; Clock.OldTick:=Clock.NewTick; Form1.Caption:=IntToStr(Clock.TimeElapsed); end; |
Selbst wenn die Zeit um 1 Millisekunde abweicht, könnte ich damit gut leben.
Viele Grüße
bummi - Mo 26.11.12 19:16
Der Cardinal läuft bein hochzählen ebenso über wie bei Rechenoperationen, das ganze ist sauber.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| Function Cardinal2Bin(c:Cardinal):String; var I: Integer; begin SetLength(Result,32); for I := 0 to 31 do begin Result[32-i] := IntToStr(Integer(c and 1))[1]; c := c shr 1; end; end;
procedure TForm3.Button1Click(Sender: TObject); var c,d:Cardinal; i:Integer; begin c := 4294967294; d := c; for I := 0 to 4 do begin memo1.Lines.Add(Cardinal2Bin(c)); inc(c); memo1.Lines.Add('Diff:' + IntToStr(c-d)); d := c; end; end; |
rushifell - Mo 26.11.12 19:34
Danke bummi. Also stimmt die Zeitmessung, wie ich sie durchführe, und es gibt auch keine Abweichung von einer Millisekunde. :D
Hat jemand eine Ahnung, ob es mit dem QueryPerformanceCounter Probleme geben kann. Oder soll ich dafür ein neues Topic erstellen?
rushifell - Mo 26.11.12 20:28
Danke, wie man den QueryPerformanceCounter verwendet, weiss ich. Meine Frage ist, ob es notwendig ist zu prüfen, ob die Differenz zwischen Startwert und Endwert negativ bzw. größer 0 ist? Schließlich wird hier ein LARGE_INTEGER zurückgeliefert, also 64 Bit signed.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| Var OldVal, NewVal, Frequency:Int64; TimeFactor:Single; Begin QueryPerformanceCounter(OldVal); ... QueryPerformanceCounter(NewVal); QueryPerformanceFrequency(Frequency); IF NewVal-OldVal>0 then TimeFactor := ((NewVal-OldVal) /Frequency) else TimeFactor:=0;
End; |
Es würde hier zwar ein Fehler in der Zeitmessung auftreten, wäre das Ergebnis jedoch negativ, wäre der Fehler wesentlich schlimmer.
WasWeißDennIch - Mo 26.11.12 20:38
Hast Du Dir einmal ausgerechnet, wann der Counter (int64) bei einer Frequenz von 1 Millisekunde überläuft? Ich denke, sollte das jemals eintreten, tangiert Dich das nicht mehr.
rushifell - Mo 26.11.12 20:47
WasWeißDennIch hat folgendes geschrieben: |
Hast Du Dir einmal ausgerechnet, wann der Counter (in64) bei einer Frequenz von 1 Millisekunde überläuft? |
Naja, ich denke wenn QueryPerformanceCounter ebenfalls die Zeit seit dem Systemstart zurückliefert, dann wie bei GetTickCount etwas weniger als 50 Tage Laufzeit des Rechners.
Natürlich ist die Wahrscheinlichkeit, dass das in der Praxis eintritt recht gering, aber dennoch denkbar. Wenn ich einen Fehler durch eine einfache Zeile Code vermeiden kann, denke ich schon, dass meine Frage gerechtfertigt ist.
Ob das ganze 'ne Millisekunde oder nicht abweicht ist letztendlich natürlich egal. Bin eben Perfektionist :zwinker:
Mathematiker - Mo 26.11.12 20:52
Hallo,
rushifell hat folgendes geschrieben : |
ob es notwendig ist zu prüfen, ob die Differenz zwischen Startwert und Endwert negativ bzw. größer 0 ist? |
Ich glaube eher nicht.
Bei 63-bit (ohne Vorzeichen) ist die größte Zahl 9223372036854775808. Bei einer Taktfrequenz von z.B. 4 GHz ergibt sich für die Variable Frequenz 4000000000 je Sekunde, d.h. rund 2,3 Milliarden Sekunden können bis zum Überlauf gezählt werden. Das sind über 70 Jahre und nicht nur 50 Tage.
Natürlich beginnt der Zähler nicht bei 0 und die Taktfrequenz ist wahrscheinlicher höher, aber am Prinzip ändert sich nichts.
Beste Grüße
Mathematiker
rushifell - Mo 26.11.12 21:02
Hoppla, grober Denkfehler meinerseits :oops:
Danke :beer:
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!