Algoritamske strategije – merenje vremena

1 Strukture i funkcije za očitavanje vremena



U datoteci <time.h> definisano je nekoliko funkcija i struktura imena tm, za očitavanje i manipulisanje vremena i datuma.


Za očitavanje vremena u ovom zaglavlju je deklarisana funkcija

time_t time(time_t *tp);

koja vraća vrednost time_t tipa, tj. kardinalni broj koji predstavlja trenutno vreme (obično je to broj sekundi od 1.1.1970.).

Parametar tp, ako nije NULL, takođe prihvata trenutno vreme u *tp.


Tip time_t je typedef za celobrojnu vrednost . U većini implementacija funkcija time()

vraća vrednost koja je jednaka vremenu u sekundama koje je proteklo od 01.1.1970. godine.

Ista se vrednost postavlja i u dereferencirani pokazivač tp, ukoliko on nije NULL.


DA LI ZNATE ZA PROBLEM 2038? (tj. problem petak 13: Tue Jan 19 03:14:07 2038 - > Fri Dec 13 20:45:52 1901)




Da bi se olakšala konverzija ovog vremena u stvarno vreme i datum, definisana je struktura tm sa sledećim članovima:


struct tm /* opisuje vreme i datum */

{

int tm_sec; /* sekunde 0..61 po knjizi Kernighan & Ritchie, vidi dole*/

int tm_min; /* minute 0..59 */

int tm_hour; /* sat 0..23 */

int tm_mday; /* dan 1..31 */

int tm_mon; /* mesec 0..11 */

int tm_year; /* broj godina nakon 1900 */

int tm_wday; /* dan u sedmici 0..6 */

int tm_yday; /* dan u godini 0..365 */

int tm_isdst; /* da li je dan promene sata 0..1 */

};



Napomena: ako dan promene sata nije implementiran tada tm_isdst ima negativnu vrednost.


Broj sekundi može biti veći od 59 u slučaju prestupnog vremena (po knjizi K&R). Meseci su kodirani tako da 0 označava januar, 1 februar itd. Dani u sedmici su kodirani tako da 0 označava nedelju, 1 ponedeljak itd.

Stvarna godina se dobije tako da se članu tm_year doda vrednost 1900

(npr. u godini 2007. godini član tm_year sadrži vrednost 107).


localtime, gmtime

Konverzija vremena iz formata time_t u struct tm vrši se funkcijom localtime(), kada se želi dobiti lokalno vreme,

ili funkcijom gmtime() za dobijanje univerzalnog vremena u nultom meridijanu.


struct tm *localtime(const time_t *t);

struct tm *gmtime(const time_t *t);


Obe funkcije primaju adresu promenljive koja sadrži vreme u formatu time_t, a vraćaju

pokazivač na statičku strukturu tipa tm (sadržaj se obnavlja pri svakom pozivu ovih funkcija) .


ctime, asctime

Ako se želi dobiti zapis vremena u obliku stringa, mogu se koristiti funkcije

char *ctime(const time_t *t);

char *asctime(const struct tm *tp);


Funkcija ctime() za argument koristi adresu promenljive koja sadrži vreme u formatu time_t,

a funkcija asctime() za argument koristi pokazivač na strukturu tm.

Obe funkcije vraćaju pokazivač statičkog stringa koji sadrži zapis vremena u standardnom formatu.


Na primer, sekvenca naredbi

time_t t = time(NULL);

char *s = ctime(&t);

puts(s);


generise ispis:

Thu Jan 25 14:21:20 2007



Uočite da je rezultat poziva ctime(&t) ekvivalentan pozivu asctime(localtime(&t)) .


Standardna verzija je prilagođena američkim standardima. Ako se želi napisati vreme u

formatu 25.01.2007 14:21

tada se može koristiti sledeće iskaz:


/* ispisuje datum i vreme u formatu 25.01.2007 14:21 */

time_t t = time(NULL);

struct tm *p = localtime(&t);

printf("%.2d.%.2d.%.2d %2d:%.2d\n",

p->tm_mday, p->tm_mon + 1,

p->tm_year +1900,

p->tm_hour, p->tm_min);





Zadatak 1: NCP koji sistemsko vreme konvertuje u string koji ispisuje na standardni izlaz.

#include <time.h>
#include <stdio.h>

struct tm *newtime;
time_t aclock;

void main( void )
{
   time( &aclock );                 /* dobijanje tekuceg vremena u sekunda */

   newtime = localtime( &aclock );  /* Konverzija vremena  u struct tm oblik */

   /* Stampa  vremena kao stringa */
   printf( "Tekuci dan i vreme su: %s", asctime( newtime ) );
}

Izlaz

Tekuci dan i vreme su: Sun Jan 21 20:27:01 2007



strftime

Funkcija strftime() se koristi za formatirani ispis vremena. Format se zadaje kao kod printf() funkcije.

Prototip funkcije strftime()glasi:

size_t strftime(char *buf, size_t bufsize, const char *fmt, const struct tm *tp);


Prvi argument je string str u koji se vrši formatirani zapis.

Drugi argument (bufsize) ograničava broj znakova stringa.

Treći parametar je string u kojem se zapisuje format ispisa nizom specifikatora oblika %x (kao kod printf() funkcije).

Poslednji argument je pokazivač strukture tm.


Funkcija vraća broj znakova u stringu ili 0 ako nije moguće generisati formatirani string.


Specifikatori formata su

%a skracenica od tri slova za ime dana u sedmici (eng. Sun, Mon, Tue,..)

%A puno ime dana u sedmici (eng...)

%b skracenica od tri slova za ime meseca (eng. Jan, Feb, Mar,...)

%B puno ime meseca (eng....)

%c kompletni zapis vremena i datuma

%d dan u mesecu (1..31)

%H sat u formatu (1..24)

%I sat u formatu (1..12)

%j dan u godini (1..366)

%m mesec u godini (1..12)

%M minut

%p AM/PM (eng.) string koji označava jutro ili popodne

%S sekunde

%U broj za sedmicu u godini (1..52) - 1 određen prvom nedeljom

%w broj za dan u sedmici (0-nedelja)

%W broj za sedmicu u godini (1..52) - 1 određen prvim ponedeljkom

%x kompletni zapis datuma

%X kompletni zapis vremena

%y zadnje dve cifre godine

%Y godina u formatu s 4 cifre

%Z ime vremenske zone (ako postoji )

%% znak %


Zadatak 2: NCP koji demonstrira korištenje funkcija za datum i vreme tako sto ih ispisuje u:

standardnom formatu (dan mesec redni_broj_dana vreme godina),

u formatiranom zapisu oblika Dan Mesec Godina Cas Minut ,

lokalno vreme.


/* Prikazuje datum i vreme u tri formata*/


#include <stdio.h>

#include <time.h>


int main()

{

time_t vreme = time(NULL); /* tekuce vreme u sekundama*/

struct tm *ptr; /* struktura za laksu konverziju tekuceg vremena u datum i vreme */

char datum_str[20]; /* string datum i vreme */



/* ispisuje datum i vreme u standardnom formatu */

puts(ctime(&vreme));


/* ispisuje datum i vreme u obliku D M G Cas Minut pomoću strftime funkcije */

strftime(datum_str, sizeof(datum_str),"%d.%m.%y %H:%M\n", localtime(&vreme));

puts(datum_str);



/* ispisuje datum i vreme u proizvoljnom formatu */

ptr = localtime(&vreme);

printf("%.2d.%.2d.%.2d %2d:%.2d\n",

ptr->tm_mday, ptr->tm_mon+1, ptr->tm_year +1900,

ptr->tm_hour, ptr->tm_min);


return 0;

}



Dobije se ispis:

Mon Jan 22 20:13:06 2007

22.01.07 20:13

22.01.2007 20:13








Za obradu vremena se koriste i sledeće funkcije:


mktime


time_t mktime(struct tm *tp)


Funkcija mktime() pretvara zapisa iz strukture tm u time_t format. Korisna je u tzv.

kalendarskim proračunima. Kada je potrebno dodati nekom datumu n dana, tada se može upisati

datum u tm strukturu, povećati član tm_mday za n, zatim pozivom mktime() se dobije

time_t vrednost koja odgovara novom datumu.


Zadatak 3: NCP koji na standardni izlaz ispisuje tekuce vreme u formatu datum i vreme, a potom ucitava od korisnika ceo broj dana i ispisuje datum i vreme nakon unetog broja dana.
#include <time.h>
#include <stdio.h>

void main( void )
{
   struct tm kada;  /* struktura za konverziju sekundi u datum i vreme */
   __time64_t sada, rezultat;  /* tekuce, buduce vreme */
   int    dani;  /* broj dana sa stdin */

   _time64( &sada );
   kada = *_localtime64( &sada );
   printf( "Tekuce vreme je %s\n", asctime( &kada ) );
   printf( "Unesite broj buducih dana: " );
   scanf( "%d", &dani );

   kada.tm_mday = kada.tm_mday + dani;
   if( (rezultat = _mktime64( &kada )) != (time_t)-1 )
      printf( "Za %d dana vreme ce biti %s\n", 
              dani, asctime( &kada ) );
   else
      perror( "_mktime64 greska" );
}

Izlaz

Tekuce vreme je Fri Jan 19 10:04:20 2007

Unesite broj buducih dana: Za 20 dana vreme ce biti Thu Feb 8 10:04:20 2007

32-bitna verzija istog programa (zbog starijih gcc kompajlera)



difftime


double difftime(time_t t1, time_t t2)

Funkcija difftime() vraća realnu vrednost koja je jednaka razlici vremena t1 i t2 u sekundama.


Zadatak 4. NCP koji ispisuje potrebno vreme za mnozenje dva realna broja koje se ponavlja 10 miliona puta

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void main( void )
{
   time_t   start, kraj;
   long i; /* brojac u ciklusu */
   double   rez, vreme;  /* rezultat mnozenja, proteklo vreme */

   printf( "Trazeno mnozenje traje...\n" );
   
   time( &start );    /* POCETAK MERENJA */
   for( i = 0; i < 10000000; i++ )
      rez = 3.63 * 5.27; 
   time( &kraj );  /* KRAJ MERENJA */

   vreme = difftime( kraj, start );
   printf( "\n %6.0f sekundi.\n", vreme );
}

Izlaz

Trazeno mnozenje traje...

 2 sekunde.

Zadatak 5. NCP koji ispisuje potrebno vreme za sabiranje dva realna broja koje se ponavlja 10 miliona puta.



2. Funkcije za merenje procesorskog vremena



clock


clock_t clock(void);


Funkcija clock() služi za preciznije merenje vremena nego sto je to moguće sa prethodnim

funkcijama. Ona vraća vrednost procesorskog merača vremena, koji startuje na početku

programa, u jedinicama koje su znatno manje od sekunde (nekoliko milisekundi). Koliko je tih

jedinica u jednoj sekundi određeno je konstantom CLOCKS_PER_SEC.

To znači da izraz: (double)clock()/CLOCKS_PER_SEC

daje vrednost koja je jednaka vremenu (u sekundama) od startovanja programa.


Zadatak 6: NCP koji ispituje vremensku rezolucija funkcije clock(), tj. minimalno vreme koje se njome može meriti,

a potom pomoću funkcije clock() izmeriti potrebno vreme za izvršenje sinusne funkcije.




#include <stdio.h>

#include <math.h>

#include <time.h>


int main()

{


double start, stop;

double n ; /* argument funkcije sinus, neinicijalizovan */

double rezolucija;



start =(double)clock()/CLOCKS_PER_SEC;


/* MERENJE REZOLUCIJE, tj. minimalnog vremena za merenje funkcijom clock */

do {

stop=(double)clock()/CLOCKS_PER_SEC;

}

while (stop == start);


rezolucija = stop-start;


printf("Rezolucija CLOCK-a je %g sekundi\n" , rezolucija);


start =(double)clock()/CLOCKS_PER_SEC;

stop = start + 10*rezolucija;


do {

n += 1.0;

sin(n);

}

while (stop > (double)clock()/CLOCKS_PER_SEC);



printf("Funkcija sin se izvršava %g sekundi\n" , 10*rezolucija/n);


return 0;

}


Izlaz:

Rezolucija CLOCK-a je 0.015 sekundi

Funkcija sin se izvrsava u 2.3543e-007 sekundi


Rezolucija funkcije clock() je 15 ms. U drugoj petlji, u kojoj se računa funkcija sin(),

odabrano je da se ona ponavlja za vreme koje je 10 puta veće od rezolucije clock()-a. Na taj

način merenje vremena izvršenja sinus funkcije vrši se s greškom koja je manja ili jednaka 10%.



Zadatak 7. NCP koji uspavljuje aktivnosti programa za 3 sekunde, a potom za dati broj ponavljanja izvrsava prazan ciklus

i meri proteklo vreme.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void sleep( clock_t cekanje );

void main( void )
{
   long    i = 600000L;  /* broj ponavljanja praznog ciklusa, tj. ciklusa bez tela */
   clock_t start, stop;
   double  vreme;  /* proteklo vreme rada */

   /* Uspavljivanje za 3 sekunde. */
   printf( "Spavam 3 sekunde\n" );
   sleep( (clock_t)3 * CLOCKS_PER_SEC );
   printf( "Probudio sam se!\n" );

   /* Merenje proteklog vremena rada ciklusa. */
   printf( "Da bi se izbrsilo %ld praznih iteracija potrebno je ", i );
   start = clock();
   while( i-- ) 
      ;
   stop = clock();

   vreme = (double)(stop - start) / CLOCKS_PER_SEC;
   printf( "%2.1f sekundi\n", vreme );
}

/* Pauza za dati broj sekundi. */
void sleep( clock_t cekaj )
{
   clock_t rez;
   rez = cekaj + clock();
   while( rez > clock() )
      ;
}

Izlaz

Spavam 3 sekunde
Probudio sam se!
Da bi se izbrsilo 600000 praznih iteracija potrebno je 0.1 sekundi

Zadatak 8. NCP koji ucitava dimenziju niza realnih brojeva, unosi niz brojeva ili u slucaju dimenzije vece od 20 generise niz slucajnih brojeva date dimenzije, a potom ih sortira metodama bubble sort i metodom quick sort. Izmeriti vreme trajanja sortiranja. Eksperimentisite sa razlicitim dimenzijama niza ( manje od 1000, vise od 1000).


#include <stdlib.h>

#include <stdio.h>

#include <time.h>

#include <string.h>


void bubble(int a[], int n);

void quick(int a[], int n);


main()

{

int *niz, *nizkopija;

clock_t s1,s2,f1,f2;

double v1,v2;

int i,n;

printf("\nUnesite dimenziju niza: \n");

scanf("%d",&n);

niz=(int *)malloc(n*sizeof(int));

nizkopija=(int *)malloc(n*sizeof(int));

for(i=0;i<n;i++) niz[i]=rand();

memcpy(nizkopija,niz,n*sizeof(int));


s1=clock();

bubble(niz,n);

f1=clock();

s2=clock();

quick(nizkopija,n);

f2=clock();

v1=(double)(f1-s1)/CLOCKS_PER_SEC; /* v1=f1-s1 */

v2=(double)(f2-s2)/CLOCKS_PER_SEC; /* v2=f2-s2 */


free(niz);

free(nizkopija);

printf("\n Bubble: %g Quick: %g\n", v1,v2);



}


void bubble( int a[], int n)

{ int i, j, b, dalje;

for(dalje=1, i=0; i< n-1 && dalje; i++)

for(dalje=0, j=n-2; j>=i;j--)

if( a[i]>a[j])

{

b=a[j]; a[j]=a[j+1]; a[j+1]=b;

dalje=1;

}

}



void quick (int a[], int n) {

int i,j,b;

if (n>1)

{

i=-1; j=n-1;

while(1)

{

do i++; while (a[i] < a[n-1]);

do j--; while (j>=0 && a[j]>a[n-1]);

if(i >= j) break;

b=a[i]; a[i] = a[j]; a[j] = b;

}

b = a[i]; a[i] = a[n-1]; a[n-1] = b;

quick (a, i); quick (a+i+1, n-i-1);

}

}


Polazna strana kursa