Sekundenweise in der Form: hh:mm:ss hochzählen



  • Hallo,

    ich möchte die Zeit eines Tages automatisch in der Form:

    hhmmss

    hochzählen.

    EDIT: und in einem Array als string ablegen!! Es geht also nicht um das Zählen in Echtzeit.

    also zB 140815 für 14h08min15sec

    also insgesamt von 000000 bis 235959

    gibt es da eine elegante Lösung?

    Mein Ansatz wäre:

    Sek, Min und Stunden einzeln als Int hochzählen, und dann "sekundenweise" in ein char Array speichern. Das erscheint mir aber etwas umständlich ....

    Danke und Grüße
    arz



  • Schau dir mal sprintf an.



  • arz schrieb:

    Sek, Min und Stunden einzeln als Int hochzählen, und dann "sekundenweise" in ein char Array speichern. Das erscheint mir aber etwas umständlich ....

    Dann wünsche ich Dir viel Spaß mit der <time.h> 😃
    Drei int- counter mit einem OVF bei 60 und sprintf() ist für die Sache wirklich einfacher, glaub' mir! 😉



  • danke schonmal,,

    das ist mir noch nicht ganz klar,,?

    hat evtl jmd ein codeschnipsel?

    Edit: bzw was mir nicht ganz klar ist:
    gibt es mit sprintf() ein konzept bei 1,2,3,4 ... eine führende Null in den string zu schreiben, so dass Sekunde 1,2,3 01,02,03 im string steht ... ?
    danke



  • Ja, das müsste mit printf("%02d",zahl); funktionieren.



  • pointercrash() schrieb:

    Drei int- counter mit einem OVF bei 60 und sprintf() ist für die Sache wirklich einfacher, glaub' mir! 😉

    Wieso drei Counter?
    Einer reicht doch. Dann noch ein bisschen mit / und % und 60 und 3600

    sec = count % 60;
    min = (count /60 ) % 60;
    std = count /3600;
    
    sprintf(buffer,"%02d%02d%02d",std,min,sec);
    

    Du kannst die Berechnung auch gleich bei sprintf machen.



  • D a n k e .

    funktioniert !



  • Bevor du jetzt selber zählst kannst du auch die time() Funktion nehmen.

    time_t seconds;
    
    count = time (NULL);
    
    sec =  count %  60;
    min = (count /  60) % 60;
    std = (count /3600) % 24;
    


  • DirkB schrieb:

    Wieso drei Counter?
    Einer reicht doch. Dann noch ein bisschen mit / und % und 60 und 3600

    sec = count % 60;
    min = (count /60 ) % 60;
    std = count /3600;
    

    Da liegt ja das Problem. Du übersiehst, wie knapp es auf Controllern zugehen kann. Eine Soft- RTC liegt meist in einem Systick- Slot als Teil einer Timer- ISR, da ist es besser, wenn die schnell bearbeitet ist. Jetzt hast Du hier vier Integer- bzw. Modulo- Divisionen, im nachfolgenden Beispiel sogar fünf, während ich mit max. drei Vergleichen auskomme:

    static char sec = 0, min = 0, std = 0;
    if (++sec >= 60){
        sec = 0;
        if (++min >= 60){
            min = 0;
            if (++std >= 24)
                std = 0;
            }
        }
    }
    

    Das ist auf einer Maschine ohne HW- Divdierer zigfach schneller.
    Davon abgesehen existiert für manche Compiler keine time- Lib, ich setze daher fast nur mein eigenes Zeug ein.



  • Abgesehen davon dass von Controllern bisher nicht die Rede war, brauchst du die Divisionen ja nur bei der Ausgabe.

    In der ISR wird counter einfach nur hochgezählt.
    Die Ausgabe läuft dann in der Mainloop und da hast du genug Zeit.



  • pointercrash() schrieb:

    Das ist auf einer Maschine ohne HW- Divdierer zigfach schneller.

    Und auf einer Maschine mit HW-Dividierer zigfach langsamer.



  • DirkB schrieb:

    Abgesehen davon dass von Controllern bisher nicht die Rede war, brauchst du die Divisionen ja nur bei der Ausgabe.

    Nö, lies' den Titel genau, das läßt keine Interpretation zu. Er will im Format hh🇲🇲ss hochzählen.

    rüdiger schrieb:

    pointercrash() schrieb:

    Das ist auf einer Maschine ohne HW- Divdierer zigfach schneller.

    Und auf einer Maschine mit HW-Dividierer zigfach langsamer.

    Was bringt Dich zu dieser kühnen Annahme? Hast Du 'nen Sack Hühnerknochen bei Neumond um Mitternacht geschüttelt und Petro beschworen, der Dir das erzählt hat? 🤡

    Gehen wir mal davon aus, daß die ISR sekündlich drankommt, dann haben wir in DirkBs letzter Routine 3600 mal Hochzählen, 5*3600 = 18'000 Divisionen und 3*3600 = 10'800 Zuweisungen pro Stunde.
    Bei mir sind's 3600 + 60 + 1, also 3661 Hochzählen mit Vergleich und 61 Zuweisungen, wenn ich mich nicht irre.

    Selbst bei HW-DIV- ALUs ist Deine Behauptung Behauptung "zigmal schneller" nichtmal über den Daumen gepeilt haltbar, bei SW-DIV beginnen die Schmerzen spätestens, wenn's mit 'nem Uhrenquarz laufen soll.



  • pointercrash() schrieb:

    DirkB schrieb:

    Abgesehen davon dass von Controllern bisher nicht die Rede war, brauchst du die Divisionen ja nur bei der Ausgabe.

    Nö, lies' den Titel genau, das läßt keine Interpretation zu. Er will im Format hh🇲🇲ss hochzählen.

    Es wäre nicht das erste mal, daß ein Thread-Ersteller bei seinem Thema meilenweit am tatsächlichen Problem vorbei schießt 😃

    @arz: Ehe hier alle Anwesenden wild herumraten: Was hast du denn mit diesem "Zähler" überhaupt vor?



  • CStoll schrieb:

    pointercrash() schrieb:

    DirkB schrieb:

    Abgesehen davon dass von Controllern bisher nicht die Rede war, brauchst du die Divisionen ja nur bei der Ausgabe.

    Nö, lies' den Titel genau, das läßt keine Interpretation zu. Er will im Format hh🇲🇲ss hochzählen.

    Es wäre nicht das erste mal, daß ein Thread-Ersteller bei seinem Thema meilenweit am tatsächlichen Problem vorbei schießt 😃

    @arz: Ehe hier alle Anwesenden wild herumraten: Was hast du denn mit diesem "Zähler" überhaupt vor?

    Ich habe Messwerte unterschiedlicher Stationen die in unterschiedlichen txt files liegen und unterschiedliche Start- und Endzeiten haben, die Zeitangaben in den txt files liegen in der Form hh🇲🇲ss. Zum Auswerten möchte ich die Daten eines Tages aller Stationen in Arrays speichern. Da es uU Lücken in den Messreihen gibt, brauche ich quasi ein Referenzzeitfeld anhand dessen ich die vorhandenen Daten dann in eine zeitliche Abfolge einsortieren kann.

    ich muss also nix in Echtzeit zählen oder einen Timer setzen, es geht nur um das Befüllen des Referenzarrays.

    Hoffe das hat geholfen ...

    Grüße!
    arz



  • pointercrash: Du kannst davon ausgehen, dass moderne Compiler (mit entsprechenden Optimierungsschaltern) Divisionen mit festen Nennern in Multiplikationen umwandeln - dabei wird ausgenutzt, dass faktisch modulo 2^Registerbreite gerechnet wird. Ob eine Division in Hardware erledigt wird oder nicht, dürfte hier also eher selten eine Rolle spielen.

    arz: Für mich klingt das so, als wolltest du eigentlich Zeiten der Form hh🇲🇲ss in Sekundenzahlen umwandeln, also genau umgekehrt. Die Mathematik ist natürlich ziemlich ähnlich:

    counter = sec + min * 60 + hour * 3600;
    

    Das kannst du dann auch direkt als Index für ein Array benutzen.



  • seldon schrieb:

    pointercrash: Du kannst davon ausgehen, dass moderne Compiler (mit entsprechenden Optimierungsschaltern) Divisionen mit festen Nennern in Multiplikationen umwandeln - dabei wird ausgenutzt, dass faktisch modulo 2^Registerbreite gerechnet wird. Ob eine Division in Hardware erledigt wird oder nicht, dürfte hier also eher selten eine Rolle spielen.

    arz: Für mich klingt das so, als wolltest du eigentlich Zeiten der Form hh🇲🇲ss in Sekundenzahlen umwandeln, also genau umgekehrt. Die Mathematik ist natürlich ziemlich ähnlich:

    counter = sec + min * 60 + hour * 3600;
    

    Das kannst du dann auch direkt als Index für ein Array benutzen.

    Ich mein's nicht persönlich, aber für welchen Planeten codet ihr? Auch gute Compiler entbinden niemanden, sein Hirn zu gebrauchen! Ich hab' jetzt aufm PC beide Lösungen nacheinander und meine durch char- Counter sogar in Nachteil gesetzt. Wer will, darf auch Timer einsetzen. Kann jetzt sein, daß Rüdiger bezweifelt, daß PCs HW-DIV- Einheiten haben, aber für den Rest der denkenden Menschheit dürfte das Ergebnis eindeutig sein.

    #define YEARSECONDS (364 * 24 * 3600)
    #define DAYSECONDS (24 * 3600)
    
    int main(int argc, char *argv[])
    {
    	int count = 0, tag = 0, std = 0, min = 0, sec = 0;
    	unsigned char cstd = 0, cmin = 0, csec = 0;
    	printf("DirkB calculates, rüdiger applauses\n");
    	for (count = 0; count <= YEARSECONDS; count++)
    	{
    		sec = count % 60;
    		min = (count /60 ) % 60;
    		std = (count /3600) % 24;
    
    		if (!(sec | min | std))
    			tag++;
    	}
    	printf("Tag: %d\n", tag);
    	printf("pointercrash() counts ...\n");
    	tag = 0; std = 0; min = 0; sec = 0;
    	for (count = 0; count <= (YEARSECONDS+DAYSECONDS); count++)
    	{
    		if (++csec >= 60){
     	   		csec = 0;
     	   		if (++cmin >= 60){
            		cmin = 0;
            		if (++cstd >= 24)
                		cstd = 0;
            	}
        	}
    		if (!(csec | cmin | cstd))
    			tag++;
    	}
    	printf("Tag: %d ... oops ...\n", tag);
    
          return 0;
    }
    

    @edit: wer mir ans Bein pissen mag, daß die Lösungen nicht völlig adäquat sind, das war mir klar, ich setz' mich um einen Tag in Nachteil, hab's nur schnell hingeschottert, um zu zeigen, wie unsinnig rüdis Behauptung ist ... 😉



  • Benchmarking mit printf ist eine ganz schlechte Idee; du hast keine Ahnung, wann der Buffer geflusht wird und verlässt dich auf dein Gefühl. Benutz clock().

    Um das zu machen, was du da tust, ist die Zählvariante natürlich schneller (sofern Branching nicht sehr, sehr teuer ist). Damit, ob die eine Division in Hardware stattfindet, hat es aber wenig zu tun, weil nicht davon auszugehen ist, dass eine Division ausgeführt wird. Der Compiler entbindet einen nicht davon, sein Hirn zu gebrauchen, aber man sollte ihn in seine Überlegungen doch einbeziehen, bevor man völlig irrelevanten Stuss über HW-Dividierer in die Diskussion wirft.

    Und da sich die Problemstellung inzwischen als eine völlig andere entpuppt hat, ist die Zählidee eh hinfällig.



  • seldon schrieb:

    Benchmarking mit printf ist eine ganz schlechte Idee; du hast keine Ahnung, wann der Buffer geflusht wird und verlässt dich auf dein Gefühl. Benutz clock().

    Das betrübt mich nun zutiefst. 😞
    Ich habe ja geschrieben, wer will, soll sich da was mit clock oder anderen Timerfunktionen was reinbasteln, aber das ist so offensichtlich, wie der Film "Bambi vs. Godzilla" kurz sein wird. Da ich meine Compiler alle in virtuellen Maschinen betreibe, wird auch clock() keine echten Benchmarkdaten liefern, man müßte das Ding profilen und das war's mir nicht wert.

    seldon schrieb:

    Um das zu machen, was du da tust, ist die Zählvariante natürlich schneller (sofern Branching nicht sehr, sehr teuer ist). Damit, ob die eine Division in Hardware stattfindet, hat es aber wenig zu tun, weil nicht davon auszugehen ist, dass eine Division ausgeführt wird. Der Compiler entbindet einen nicht davon, sein Hirn zu gebrauchen, aber man sollte ihn in seine Überlegungen doch einbeziehen, bevor man völlig irrelevanten Stuss über HW-Dividierer in die Diskussion wirft.

    Häh? Wenn man aus einem Counter std, min, sec extrahiert, geht das nur durch Division, arz braucht den Tag sekundenweise hochgezählt, um eine Zeitskala zu erhalten. Dabei wird sehr wohl relevant, ob man einen HW- Dividierer hat, war ja Rüdigers These, daß damit die Divisionslösung schneller wird als Hochzählen. In Software hat die Divisionslösung aus ersichtlichen Gründen Null komma gar keine Chance und auch mit HW-DIV bleibt die Divisionslösung dimensional langsamer, ist mitnichten "zigmal schneller", wie rüdiger in einem Anfall geistiger Verwirrung geschrieben hat - nichts anderes belegt mein Codeschnipsel. Eher ist Dein Einwand mit den Branching irrelevant, das kann niemals teurer sein, als fünf Int/Mod- Divs.

    seldon schrieb:

    Und da sich die Problemstellung inzwischen als eine völlig andere entpuppt hat, ist die Zählidee eh hinfällig.

    Eben nicht, arz braucht ja alle Tagessekunden als String. Ich habe das sprintf (oder fprintf, whatsoever) weggelassen, um deutlich zu machen, daß Zählen schneller ist als Dividieren, q.e.d.
    Die Ausgabefunktionen sind abartig lahm, demgegenüber würde es weniger ins Gewicht fallen, daß Dividieren langsamer ist. Auch, wenn es nur um das Füllen eines array von Strings geht, ist Hochzählen schneller, viel schneller sogar. 😃



  • Lies das hier. Diese Optimierung wird von allen gängigen Compilern benutzt. Du wirst im Maschinencode keine Divisionen bekommen, weil die Divisoren allesamt konstant sind und die Divisionen zu Multiplikationen und Bitshifts optimiert werden.

    Greif dir mal nen gcc, nudel den Kram durch und schau in den Maschinencode. Eine Division durch 3600 wird zu

    movl	$-1851608123, %edx
    	movl	%ecx, %eax
    	imull	%edx
    	leal	(%rdx,%rcx), %eax
    	movl	%eax, %edx
    	sarl	$11, %edx
    	movl	%ecx, %eax
    	sarl	$31, %eax
    

    ...und da ist noch nicht mal ein -O-Schalter drin.

    Was die Aufgabenstellung angeht -- so wie ich das lese, hat arz eine Datei voll mit derart formatierten Zeitstempeln und muss diese in ein Kontinuum einordnen. Dazu wäre dann genau die umgekehrte Umwandlung sinnvoll.



  • seldon schrieb:

    Lies das hier.

    Jo, die Sache mit Shift und mul ist uralt, der LCC macht's genauso, wobei noch nicht endgültig geklärt ist, ob diese Optimierung für den X86 noch Sinn macht. Zumindest wird kein HW- DIV bemüht.
    Wobei die Inkrementiersequenz immer noch wesentlich schneller läuft.

    seldon schrieb:

    Was die Aufgabenstellung angeht -- so wie ich das lese, hat arz eine Datei voll mit derart formatierten Zeitstempeln und muss diese in ein Kontinuum einordnen. Dazu wäre dann genau die umgekehrte Umwandlung sinnvoll.

    Ja, wahrscheinlich wäre das sinnvoller gewesen. Aber ob er's so macht, da hätte er ja fragen müssen, ob man drei Multiplikationen und zwei Additionen durch was praktischeres ersetzen kann - da hätte ich eher Trollerei vermutet. Gefragt hat er nach Zeitstrings im Format std:min:sec und die produzier' ich schneller mit Hochzählen. 😃



  • noch einen nachtrag hierzu:

    ich habe mich jetzt entschieden die Zeit als string auszulesen und habe also einen string der Form:

    hhmmss

    Daraus möchte ich direkt einen Index für ein array erzeugen.

    also :

    index = hh*3600+mm*60+ss

    wie kann ich den string in 3 int-Werte zerlegen?


Anmelden zum Antworten