PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++ Map mit Zeitdatentyp als Schlüssel


Godmode
2007-08-08, 09:35:26
Ich habe wieder mal ein kleineres C++ Problem und zwar geht es um folgendes:

Ich lese aus mehreren Dateien eine Reihe von Messwerten aus. Der Startzeitpunkt der Aufzeichnung der Messwerte ist bekannt, sowie auch die Taktung (1 ms). Diese Messwerte möchte ich nun in eine Map speichern, wobei ich für jeden Messwert den Messzeitpunkt als Schlüssel verwenden möchte.

Pseudocode:
map<zeittyp, doulbe> messwerte();
double wert;
long i = 0;
zeittyp startpunkt = MesswerteStartzeitpunkt(...);
zeittyp zeit;

foreach(wert in MesswerteAusDatei(...))
{
zeut = startpunkt + i;
messwerte[zeit] = wert ;
i++;
}

Ich hab jetzt folgende Prolbeme:
-Was für einen Typ verwende ich am besten für die Zeit?
-Gibt es eine Funktionen, die einen String (der die Zeit enthält in Form von "10.07.2007 13:55:20.994000") in einen Zeittyp umwandelt, oder muss ich mir was eigenes schreiben?

Coda
2007-08-08, 11:16:54
Ich würd einfach einen 64-Bit-Integer in Unix Time nehmen. Oder du verwendest wenn das Format überall gleich ist einfach std::string.

transstilben
2007-08-08, 13:17:32
Als Datentyp sollte ein unsigned int (32 Bit) IMHO völlig reichen. Das spart vielleicht auch ein bißchen Platz.

Godmode
2007-08-08, 13:17:44
Danke, hat funktioniert!

Coda
2007-08-08, 13:40:53
Als Datentyp sollte ein unsigned int (32 Bit) IMHO völlig reichen. Das spart vielleicht auch ein bißchen Platz.
Wenn man das Jahr mit reinrechnen muss wird das aber schwierig bei ms-Genauigkeit.

Danke, hat funktioniert!
Was denn nun? ;)

Godmode
2007-08-08, 13:43:54
Wenn man das Jahr mit reinrechnen muss wird das aber schwierig bei ms-Genauigkeit.


Was denn nun? ;)

Ja hab nur deinen Beitrag gelesen, der andere kam erst später.

edit: machs jetzt mit nem 64 bit Integer

Godmode
2007-08-08, 14:05:54
Könnt ihr mich noch sagen ob es eine Funktion gibt, die einen String "10.07.2007 13:55:20.994000" in einen Zeittyp umwandelt, oder muss ich mir das selber schreiben? Ich bekomme die Startzeit aus der Datei leider nur als String raus.

Coda
2007-08-08, 14:18:28
Ich würd höchstens den String parsen und Jahr, Uhrzeit, usw. rausextrahieren und dann die C-Funktionen nehmen um es in Unix-Zeit umzurechnen. Das ist nämlich alles andere als trivial.

transstilben
2007-08-08, 14:22:56
Wenn man das Jahr mit reinrechnen muss wird das aber schwierig bei ms-Genauigkeit.


Ich würde es so machen: Für den Startzeitpunkt der Messung
definiere ich unsigned int start_timestamp = 0.

Für alle weiteren Messpunkte speichere ich die seit diesem Startzeitpunkt
vergangenen Millisekunden ebenfalls als unsigned int.
Damit kann eine Messung maximal 49 Tage dauern. Würde mich sehr wundern
wenn das nicht reichen sollte. Was hat das Jahr in der Map zu suchen ?
Das ist doch in der Regel bekannt und immer gleich !
Vielleicht habe ich aber auch die Problemstellung missverstanden ? :smile:

del_4901
2007-08-08, 14:25:42
Reicht es nicht einfach alle nicht Ziffern zu löschen, und die daraus existierende Zahl zu parsen?

Godmode
2007-08-08, 15:11:31
Danke für die guten Vorschläge! Ich hab das Problem jetzt folgendermaßen gelöst:

Ich parse den Zeitstring und fülle damit die einzelnen Teile der Struktur SYSTEMTIME (wYear, wMonth,...). Dann wandle ich dieses Struktur mittels SystemTimeToFileTime(&st, &ft); in das FILETIME Format um. FILETIME wandle ich dann in den Typ LARGE_INTEGER, damit ich das ganze einfach manpulieren kann.

Die 64 bit Integer Zeit kann ich nun pro Messpunkt um eine bestimmte Anzahl von 100 ns erhöhen. Dadurch kann später zu jedem Messpunkt die absolute Zeit dargestellt werden.

Der Code ist wird nur auf Windows laufen, da die Messwert-Auslese-Bibliothek nur für Windows verfügbar ist.

Xmas
2007-08-08, 15:15:17
Warum überhaupt eine Map, wenn Startzeit und Taktung bekannt sind?

Besserwissend
2007-08-08, 15:32:09
Warum überhaupt eine Map, wenn Startzeit und Taktung bekannt sind?
Frag ich mich auch. Ein einfaches (dynamisches) Array reicht doch.
Man kann sogar die vergangenen ms nach Messstartzeit als Indizes benutzen.

[index][inhalt]
-------------
[0][Startzeitpunkt] (Startzeit in ms nach 1970)
[1][1. MW] (nach 1ms)
[2][2. MW] (nach 2ms)
...

Wozu brauch man überhaupt eine Startzeit bei vorhandener Taktung?

Godmode
2007-08-08, 15:41:09
Frag ich mich auch. Ein einfaches (dynamisches) Array reicht doch.
Man kann sogar die vergangenen ms nach Messstartzeit als Indizes benutzen.

[index][inhalt]
-------------
[0][Startzeitpunkt] (Startzeit in ms nach 1970)
[1][1. MW] (nach 1ms)
[2][2. MW] (nach 2ms)
...

Wozu brauch man überhaupt eine Startzeit bei vorhandener Taktung?

Es werden mehrere Dateien eingelesen, wobei die Reihenfolge der Dateien nicht der Aufzeichnungsreihenfolge entsprechen muss. Dein Vorschlag würe nur funktionieren, wenn ich nur mit einer Datei arbeiten würde.

Ich habe mich deshalb für die Map entschieden, da die Daten dann schön sortiert sind, bzw sich einfach sortieren lassen.

Meinst du mit dynamischen Array einen Vektor oder sowas: float* = new float[length]?

Die Daten werden an eine andere Anwendung weitergegeben und diese will sie im Format
Liste = {Paar}
Paar = <Messzeitpunkt, Messwert>

Besserwissend
2007-08-08, 19:42:00
Es werden mehrere Dateien eingelesen, wobei die Reihenfolge der Dateien nicht der Aufzeichnungsreihenfolge entsprechen muss. Dein Vorschlag würe nur funktionieren, wenn ich nur mit einer Datei arbeiten würde.

Ich habe mich deshalb für die Map entschieden, da die Daten dann schön sortiert sind, bzw sich einfach sortieren lassen.

Meinst du mit dynamischen Array einen Vektor oder sowas: float* = new float[length]?

Die Daten werden an eine andere Anwendung weitergegeben und diese will sie im Format
Liste = {Paar}
Paar = <Messzeitpunkt, Messwert>
Ich meinte das ungefähr so (ich hoffe ich hab die Problemstellung richtig verstanden):

Ich gehe mal von einer flachen ASCII-Datei aus:
etwa so???

-------------------------------------
starttime=10.07.2007 13:55:20.994000
MW1
MW2
MW3
MW4
...
----------------------------------------



Pseudocode:

double result[1000000]; // Anzahl der Meßwerte, das Ergebnisfeld reicht für 1000s, ca. 16 Min.
double starttime;
double temp;
double minStartTime = 99999999999; // früheste Startzeit in ms

// bestimme früheste Startzeit aller Dateien (quasi der Meßbeginn)

foreach ( file in filename ) {
open ( file );
temp = timeConvert2ms( substring-before( substring-after( '=', readline (file, x)),';' ) )
minStartTime = ( temp < minStartTime )? temp : minStartTime;
close ( file );
}


// Einlesen der Meßwerte
foreach ( file in filename ) {

open ( file );
starttime = substring-before( substring-after( '=', readline (file, x)),';' );
temp = timeConvert2ms ( starttime ) - minStartTime; // aktuelle (relative) Startzeit

// hier werden die einzelnen Werte einglesen
while ( notempty( file ) ) {
result[temp] = readline( file ); ;
++temp;
}
close ( file );
}


Als Ergebnis kommt ein Feld heraus, mit dem man für einen Zeitpunkt t einen zugehörigen Meßwert mit "result[t]" bestimmen kann.
(z.B. Meßwert zum Zeitpunkt 10ms nach Meßbeginn: result[10])
Vorteil: wesentlich schnellerer Zugriff auf die Meßwerte, als mit einer Map, kein Speicherplatz geht für die Datenstruktur drauf, einfacher auszuwerten, zu sortieren, etc.

Godmode
2007-08-08, 23:36:14
Ich meinte das ungefähr so (ich hoffe ich hab die Problemstellung richtig verstanden):

Ich gehe mal von einer flachen ASCII-Datei aus:
etwa so???....
....


Das wäre ja keine schlechte Idee, aber ich müsste dazu quasi ein Array mit 84.000.000 Elementen anlegen, wenn ich Daten von einem Tag bearbeiten will. Es können auch Lücken drinnen sein, zb wenn ich Messdaten von 0:00-12:00 Uhr und von 18:00-23:00 habe. Würde ich ein Array verwenden, wäre ich gezwungen das Array 84 Mio. Elemente groß zu machen obwohl ich nur 61,2 Mio Messwerte speichern müsste (1 ms Auflösung).

Wie ich weiter oben schon erwähnt habe, muss die genaue absolute Zeit an das andere Programm übergeben werden und das in Form einer Liste von Wertepaaren (Messzeitpunkt, Messwert).

Chris Lux
2007-08-08, 23:57:38
vielleicht hilft dir auch boost::date_time (http://www.boost.org/doc/html/date_time.html) weiter.

Neomi
2007-08-09, 02:00:29
Würde ich ein Array verwenden, wäre ich gezwungen das Array 84 Mio. Elemente groß zu machen obwohl ich nur 61,2 Mio Messwerte speichern müsste (1 ms Auflösung).

In dem Fall wäre das overheadlose Array immer noch speicherschonender als eine std::map, die noch einiges an Strukturinformationen mit rumschleppen muß, daher ein schlechtes Beispiel. Du solltest schon deutlich mehr Lücken als tatsächliche Werte haben (oder richtig speicherintensive Werte, zu denen "double" sicher nicht gehört), um mit einer std::map besser zu fahren.

Godmode
2007-08-09, 11:38:12
Habe jetzt mal ein Array und eine Map mit 86 Mio. Werten befüllt und der Laufzeitunterschied ist brutal. Werde die Implementierung mal mit nem Array versuchen und die Absolutzeit erst bei der Übergabe an das andere Programm berechnen.