Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: So Jul 06, 2025 12:22

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Autor Nachricht
BeitragVerfasst: Mo Jun 27, 2011 15:35 
Offline
DGL Member

Registriert: Sa Okt 18, 2008 11:59
Beiträge: 180
Moinsen.

Ich arbeite an einem "timerEventManager". Das Teil ist dafür da um zeitliche Ereignisse (Funktionen) (ähnlich einem Timer) aufzurufen.
Noch nicht ausgiebig getestet, aber ich geh jetzt mal davon aus das mein überaus geistreiches Genie das alles richtig gemacht hat (andernfalls muss ich noch ein wenig entbuggen^^).
Dabei nutz ich übrigens die Windowsfunktionen (QueryPerformanceFrequency und QueryPerformanceCounter).

Problem:
Das Teil soll nicht nur mit einmal-Aufruf-Funktionen arbeiten sondern teils auch periodische Ereignisse (wie ein Timer eben) aufrufen:
DAZU gibt es einen double für den nächsten Aufrufzeitpunkt und einen weiteren double für das Zeitintervall zwischen 2 Aufrufen. Wird also der nächste Aufrufzeitpunkt erreicht wird das Zeitintervall draufaddiert (und vorher die entsprechende Funktion aufgerufen).
Schwierigkeit ist hierbei das ein Ereignis auch 1000 mal (oder öfters) pro Sekunde aufgerufen werden kann. "Round-Off"-Errors dürften da mit Sicherheit auftreten.
Brüche sind mit doubles nicht darstellbar (3mal die Sekunde (also ein Drittel) wäre selbst bei 100%-iger exakter Dezimaldarstellung nicht möglich (0,3333....)).

Ich hatte jetzt eigentlich nicht vor mir ein extrem-professionelles-ultra-krasses-Algebra-Bruchrechnungs-dingsbums selbst zu programmieren.
Gibts da was fertiges oder ein gutes tutorial?


Das in Klammern gesetzte im Titel soll nur darauf hinweisen das es auch eine extra-Klasse für die Berechnungen sein darf.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 27, 2011 17:05 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Gibts da was fertiges

Klar, z.B. die GNU Multiple Precision Arithmetic Library (GMP) bzw. GNU MPFR.

ABER...bist du sicher das du dies überhaupt brauchst? Die Auflösung von Double ist deutlich höher als die Auflösung des QueryPerformanceCounter. Zudem gibt es noch andere Threads und Programme die auch CPU-Zeit brauchen. Messe lieber die tatsächlich vergangene Zeit und summiere den Fehler auf. Beim nächsten Frame wartest du dann entsprechend kürzer oder länger.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 27, 2011 17:33 
Offline
DGL Member

Registriert: Sa Okt 18, 2008 11:59
Beiträge: 180
"Messe lieber die tatsächlich vergangene Zeit und summiere den Fehler auf. Beim nächsten Frame wartest du dann entsprechend kürzer oder länger."

Dazu müsste ich wissen wie groß der Fehler ist.



Ausserdem befürche ich das dann quasi ein Ereignis vor einem anderen ausgeführt werden könnte, auch wenn dies eigentlich nicht passieren soll.
Beispiel:
1. Ereignis wird alle 0,5 Sekunden ausgelöst.
2. Ereignis wird jede Sekunde ausgelöst.

Durch die Reihenfolge müsste 2mal das 1. Ereignis und danach einmal das 2. Ereignis aufgerufen werden.
Ich rechne damit das praktisch auch sowas wie:
-3mal Ereignis 1
-1mal Ereignis 2
-1mal Ereignis 1
-1mal Ereignis 2
-2mal Ereignis 1
-1mal Ereignis 2
... auftreten könnte.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 27, 2011 18:15 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Dazu müsste ich wissen wie groß der Fehler ist.

"Tatsächliche Zeit" - "gewünschte Zeit"

Zitat:
Ausserdem befürche ich das dann quasi ein Ereignis vor einem anderen ausgeführt werden könnte, auch wenn dies eigentlich nicht passieren soll.

Sicher das du das brauchst? Sind die Ereignisse wirklich voneinander abhängig?

Bei deinem Beispiel kannst du doch auch einfach ein Ereignis nehmen welches den "Ereignis 2"-Teil einfach nur bei jedem zweiten mal ausführt. Kannst du auch zu einem gewissen Grad verallgemeinern...eben den größten gemeinsamer Teiler suchen und entsprechende Vielfache berechnen.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 27, 2011 18:23 
Offline
DGL Member

Registriert: Sa Okt 18, 2008 11:59
Beiträge: 180
""Tatsächliche Zeit" - "gewünschte Zeit""
Wie gesagt, dazu müsste ich den EXAKTEN Wert von "Tatsächliche Zeit" wissen. Dieser wäre dann ein double mit Rundungsfehler und gewünschte Zeit wäre ja quasi auch ein double mit Rundungsfehler. Oder wie meinst du das? Kapier ich nicht so ganz.
Zudem ist ja weiterhin ein Bruch nicht so ganz darstellbar.

Ich bin halt kleinlig was die Präzision angeht.^^


"Sicher das du das brauchst? Sind die Ereignisse wirklich voneinander abhängig?"

Das war nur ein BEISPIEL (stand ja auch da). Ob ich das brauche? Keine Ahnung wollte es frei-verfügbar machen (falls überhaupt an sowas Interesse besteht), --> die Frage müsste daher lauten: "Brauchen andere das vielleicht?".


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 27, 2011 19:04 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Dieser wäre dann ein double mit Rundungsfehler und gewünschte Zeit wäre ja quasi auch ein double mit Rundungsfehler.

Richtig. Du liegst innerhalb der Genauigkeit des QueryPerformanceCounter. Die Rundungsfehler sollten sich eigentlich im Mittel gegenseitig ausgleichen. Was du zusätzlich machen kannst ist größere Zeitabstände (*) zu messen und diese zum ausgleichen zu benutzen. Zum zwischenspeichern von Zeitpunkten benutzt du natürlich den LARGE_INTEGER den dir der PerformanceCounter zurückgibt, die Umwandlung nach double (und in die Einheit Sekunden) machst du erst wenn du sie wirklich brauchst.

Mehr geht ohne entsprechende Spezialhardware nicht.


(*) etwa einen Zeitstempel alle 10 sowie alle 100 Frames speichern.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 27, 2011 19:15 
Offline
DGL Member

Registriert: Sa Okt 18, 2008 11:59
Beiträge: 180
Die Umwandlung von LARGE_INTEGER zu double wäre nicht das Problem da ich bereits dafür Referenzpunkte verwende um die verstrichene Zeit zu berechnen.
Der Referenzpunkt wird nur dann neu gesetzt, wenn der eventManager pausiert wird oder die Zeitskalierung sich verändert (ich setze das einfach mal als unwichtig fest).

Problem ist nur das dauernde draufaddieren von Zeitintervallen bei Ereignissen die häufig (mehrmals die Sekunde) ausgeführt werden, insbesondere dann, wenn diese einen Bruch haben (z. B. ein drittel).


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 27, 2011 19:22 
Offline
Ernährungsberater
Benutzeravatar

Registriert: Sa Jan 01, 2005 17:11
Beiträge: 2068
Programmiersprache: C++
Wäre es dann nicht das sinnvollste in einem Format zu speichern wo keine Brüche notwendig sind?
z.B die Einheit verkleinern und alles in Ganzzahlen zu haben?

_________________
Steppity,steppity,step,step,step! :twisted:
❆ ❄ ❄ ❄ ❅ ❄ ❆ ❄ ❅ ❄ ❅ ❄ ❅ ❄ ❄
❄ ❄ ❄ ❅ ❄ ❄ ❄ ❅ ❄ ❄ ❆ ❄ ❄


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 27, 2011 19:26 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Problem ist nur das dauernde draufaddieren von Zeitintervallen bei Ereignissen die häufig (mehrmals die Sekunde) ausgeführt werden, insbesondere dann, wenn diese einen Bruch haben (z. B. ein drittel).

Deswegen ja die tatsächliche Zeit über längere Zeiträume (z.B. 10 oder 100 Intervalle) messen, statt die Intervalle auf zu addieren.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 27, 2011 19:32 
Offline
DGL Member

Registriert: Sa Okt 18, 2008 11:59
Beiträge: 180
i0n0s erläutere mir das mal näher. Ohne Brüche wäre halt ein-drittel nicht darstellbar oder wie meinst du das?

Coolcat: meinst du mit Referenzpunkten wie ichs beim eventManager selbst mache? (siehe letzten Beitrag von mir)
An sich ginge das, wenn denn das Intervall entsprechend präzise ist.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Jun 27, 2011 19:47 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Coolcat: meinst du mit Referenzpunkten wie ichs beim eventManager selbst mache?

Äh, ja vom Prinzip genau das...hatte deinen Beitrag wohl nicht richtig gelesen. Der Referenzpunkt muss natürlich ein LARGE_INTEGER sein. Wenn der Referenzpunkt zu weit in der Vergangenheit liegt wird aber die Umwandlung in double schwierig. (Je größer die Zahl, desto mehr Nachkommastellen verlierst du) Ich denke das sinnvollste ist es die Soll-Zeit ebenfalls in "Ticks" zu berechnen um dann eben die Differenz zur Ist-Zeit ebenfalls als Integer rechnen zu können.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Jun 28, 2011 13:08 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2623
Wohnort: Berlin
Programmiersprache: Go, C/C++
Im Linux Bereich hab ich die Präzisionsprobleme nicht wirklich aber trotzdem gibt es ja noch problematiken mit der Fehlertolleranz. Um das ganze auch recht performant zu halten machen ich folgendes.

Aktueller Zeitstempel holen,das Interval drauf rechnen und den Wert hinterlegen(z.B. sortierte liste). Der Thread/Funktion holt sich dann den aktuellen timestamp, prüft ob der nächste Task dran wäre.
Code:
  1. TimeSpan now(DateTime::Now().ToTimeSpan());
  2. while (now<m_NextTask.Front()->At)
  3. {
  4.   m_NextTask.Front()->Exec();//callback
  5.   ITask* task=m_NextTask.Pop();//entferne aus der todo
  6.   task->At+=task->Frequence;//addiere das Interval drauf, sollte die 3fache Zeit verstrichen sein, dann wird der task halt 3x aufgerufen(gerade bei simulation wichtig)
  7.   m_NextTask.Push(task);//in die todo,der task liegt nicht unbedingt am ende, wegen sortierung
  8. }
  9. Thread::Sleep(max(0,(m_NextTask.Front->At-now).TotalMicroSeconds()));//warte garnicht oder die Zeit bis zum nächsten task


Man kann kein genaues Sleep hin bekommen, welches ohne check aus kommt. Der Versuch ist verschenkte Zeit, da Sleep sehr ungenau ist und jedes mal an ner anderen Zeit raus kommt, noch dazu wird jedes mal die Tolleranz mit drauf summiert, so das man nach 24h z.B. 1minute versatzt haben könnte. Daher nimm lieber die obere TimeStamp Variante.
Wenn die Präzision des Sleeps besser sein soll, dann kann man das nur auf kosten der CPU, mit niedrigeren intervalle für die checks.

Man sollte die Zeit so selten wir möglich holen(sehr langsamer system call), daher wir das now nicht nach einem erfolgreichen task neu geholt. Operationen mit 64Bit variablen sind nicht so billig und gerade an so einer kritischen Stelle summieren sich jegliche Art von Operationen zu nen riesen Berg an verschenkter CPU-Zeit auf.
Daher wurde die Addition von Intervalllänge und Zeitstempel beim hinzufügen, des Task gemacht und muss nicht bei der Prüfung jedes mal (Zeitstempel-LetzterZeitstempel)>Interval machen.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.011s | 15 Queries | GZIP : On ]