[C] (funkcja CLOCKS_PER_SEC i clock() ) Czas obliczeń stale wynosi 0.000.

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

int silnia();

int main(void) {
	int a, wynik;
	
	printf("Podaj, ktory wyraz ciagu (silnia) chesz wpisac\nGdy podasz ujemna liczbe, funkcja zwroci 0\nPodales: ");
	scanf("%d", &a);
	
/*tutaj*/	clock_t start = clock();
	
	wynik = silnia(a);
	
/*tutaj*/	clock_t end = clock();
	double time_spent = (double) (end - start)/ CLOCKS_PER_SEC;
	printf("Ten wyraz ciagu silnia ma wartosc %d\n", wynik);
	printf("Czas obliczen to: %lf", time_spent);
	return 0;
}

int silnia(x){
	if(x<0){
		return 0;
	}
	else if(x<2){
		return 1;
	}
	
	return x * silnia(x-1);
}
	

Dlaczego czas działania programu jest stale równy 0.000?

0

W debugerze możesz sprawdzić, że wartość start i end są najpewniej takie same, stąd wynik będzie 0.00. Sprawdź jak zdefiniowano CLOCKS_PER_SEC. Najpewniej będzie to wartość 1000, czyli jeden cykl to milisekunda. To wystarczy aby wykonywanie obliczeń silni w Twoim programie mieści się w jednym cyklu zegara.

Zamiast clock użyj std:

auto start = std::chrono::system_clock::now();

/* do some work */

auto end = std::chrono::system_clock::now();
auto elapsed = end - start;
0

Jakiego środowiska używasz? Ile wynosi u Ciebie CLOCKS_PER_SEC? Czy end - start jest większe od 0 w Twoich przypadkach?
SOA#1 U mnie po kompilacji kod pokazał niezerowe czasy. Możesz mieć np. zdefiniowane CLOCKS_PER_SEC jako 1000 w systemie i wtedy pomiary w odstępach mniejszych niż 1ms pokażą Ci różnicę czasu 0, bo nie minął Tick zegara pomiarowego.
Więcej info:
Wikibooks
StackOverflow

0

Używam Dec C++ (szczegółów nie podam w tej chwili). Na zajęciach korzystamy z Dev C++ i były osoby, którym to działało.
Co mogę zrobić w takim razie?
Ps: Do wikibooks sam dotarłem, a ten drugi link jutro przejrzę dokładniej.

0

Zależnie od systemu, na którym uruchamiasz kod:

  • Dla Windowsa używasz QueryPerformanceCounter z windows.h MSDN
  • Dla Linuxa możesz użyć funkcji z POSIX API clock_gettime: manual
0
  1. W kwestii formalnej CLOCKS_PER_SEC to nie funkcja tylko stała
  2. najprawdopodobniej popełniasz powszechny błąd dzielenia na typach całkowitych (w którym tracisz część ułamkową), późniejsze rzutowanie na double korzysta już niedokładnego typu całkowitego
0
AnyKtokolwiek napisał(a):
  1. W kwestii formalnej CLOCKS_PER_SEC to nie funkcja tylko stała

A czy ktoś tu napisał, że to funkcja?

  1. najprawdopodobniej popełniasz powszechny błąd dzielenia na typach całkowitych (w którym tracisz część ułamkową), późniejsze rzutowanie na double korzysta już niedokładnego typu całkowitego

Nie popełnia tego błędu. Operator rzutowania ma pierwszeństwo nad operatorem dzielenia.

1

Wydrukuj sobie wartość CLOCKS_PER_SEC i zastanów się, czy nie jest ona za mała (na Windows Visual Studio mam 1000, na Linux 1000000, a to daje odpowiednio rozdzielczość 1ms i 1μs).
Sam problem silni jest dość prosty, maksymalny sensowny argument to 12 (taki wynik mieści się w int), zakładając, że jedna iteracja to około 20 cykli razy 12 iteracji, a CPU jest taktowane >2GHz to szacunkowy czas wykonania to: 120 ns (czyli 10 razy za mało, żeby coś zaobserwować na Linux).

0
GutekSan napisał(a):
AnyKtokolwiek napisał(a):
  1. W kwestii formalnej CLOCKS_PER_SEC to nie funkcja tylko stała

A czy ktoś tu napisał, że to funkcja?

PP (Pierwotny Pytający)

0
LARGE_INTEGER start;
	LARGE_INTEGER end;
	
	printf("Podaj, ktory wyraz ciagu (silnia) chesz wpisac\nGdy podasz ujemna liczbe, funkcja zwroci 0\nPodales: ");
	scanf("%d", &a);
	
	clock_t start = QueryPerformanceCounter(LARGE_INTEGER start);
		
	wynik = silnia(a);
	
	clock_t end = QueryPerformanceCounter(LARGE_INTEGER end);
	
	double time_spent = (double) (end - start)/ CLOCKS_PER_SEC;

Tak to teraz wygląda. Kompletnie nie mam pojęcia, jak tego użyć.
1
Poczatkujacy99 napisał(a):
LARGE_INTEGER start;
	LARGE_INTEGER end;
	
	printf("Podaj, ktory wyraz ciagu (silnia) chesz wpisac\nGdy podasz ujemna liczbe, funkcja zwroci 0\nPodales: ");
	scanf("%d", &a);
	
	clock_t start = QueryPerformanceCounter(LARGE_INTEGER start);
		
	wynik = silnia(a);
	
	clock_t end = QueryPerformanceCounter(LARGE_INTEGER end);
	
	double time_spent = (double) (end - start)/ CLOCKS_PER_SEC;

Tak to teraz wygląda. Kompletnie nie mam pojęcia, jak tego użyć.

W dokumentacji masz przykład. Tak ciężko znaleźć i skopiować?

Nie zapomnij zlinkować Kernel32.lib lub załadować Kernel32.dll.

0

Funkcja main teraz prezentuje się w ten sposób:

int main(void) {
	int a, wynik;
	__int64 ctr1 = 0, ctr2 = 0, freq = 0;
	double czas;
	
	printf("Podaj, ktory wyraz ciagu (silnia) chesz wpisac\nGdy podasz ujemna liczbe, funkcja zwroci 0\nPodales: ");
	scanf("%d", &a);
	
	QueryPerformanceCounter((LARGE_INTEGER *)&ctr1);
		
	wynik = silnia(a);
	
	QueryPerformanceCounter((LARGE_INTEGER *)&ctr2);
	czas = (double)(ctr2 - ctr1) * 1.0 / 
	
	printf("Ten wyraz ciagu silnia ma wartosc %d\n", wynik);
	printf("Czas obliczen to: %lf", czas);
	return 0;
}

Na ekranie wreszcie się coś pojawia, ale raczej nie o to chodziło: -1.#IND00
Próbowałem zainkludować #include <Kernel32.lib>, ale wyskakiwał jakiś błąd. Dodałem w ten sposób bibliotekę windows.h...
Nie będę udawał, że wszystko wiem i już działa, dlatego dalej piszę. Proszę o wyrozumiałość.

1
Poczatkujacy99 napisał(a):

Funkcja main teraz prezentuje się w ten sposób:

int main(void) {
	int a, wynik;
	__int64 ctr1 = 0, ctr2 = 0, freq = 0;
	double czas;
	
	printf("Podaj, ktory wyraz ciagu (silnia) chesz wpisac\nGdy podasz ujemna liczbe, funkcja zwroci 0\nPodales: ");
	scanf("%d", &a);
	
	QueryPerformanceCounter((LARGE_INTEGER *)&ctr1);
		
	wynik = silnia(a);
	
	QueryPerformanceCounter((LARGE_INTEGER *)&ctr2);
	czas = (double)(ctr2 - ctr1) * 1.0 / 
	
	printf("Ten wyraz ciagu silnia ma wartosc %d\n", wynik);
	printf("Czas obliczen to: %lf", czas);
	return 0;
}

A gdzie masz:

QueryPerformanceFrequency((LARGE_INTEGER *)&freq);

?

Oprócz tego:

czas = (double)(ctr2 - ctr1) * 1.0 / freq;

Próbowałem zainkludować #include <Kernel32.lib>

Przez #include załączasz jedynie pliki nagłówkowe. Kernel32.lib jest plikiem binarnym, skompilowaną biblioteką. Dodajesz go w opcjach linkera. Jeśli program Ci się zbudował i uruchomił, to chyba masz już dodaną tę bibliotekę domyślnie.

-1.#IND00 to efekt dzielenia przez 0.

0

Dodałem to, o czym zapomniałem. Aktualnie program czasami pokazuje dla 4 wartość 0.000001, a dla dalszych wyrazów ciągu 0.000000 (dla 6, 7, 9 też raz się zdarzyło pokazać 0.000001), co jest dosyć dziwne.
Jeszcze znalazłem na internecie takie coś http://obrazki.elektroda.net/8_1224953000.png Dodałem w to miejsce wypakowany plik kernel32.dll pobrany z jakiejś strony na internecie i też żadnego efektu :(

0
Poczatkujacy99 napisał(a):

Dodałem w to miejsce wypakowany plik kernel32.dll pobrany z jakiejś strony na internecie i też żadnego efektu :(

Nigdy nie rób takich rzeczy

2

Przecież opisałem ci na czym polega problem z clock! Ten sam problem możesz mieć z QueryPerformanceCounter.
Dałem ci linka do QueryPerformanceFrequency jaką wartość zwraca?
Dałem linka do opisu jak tego używać i jakie są pułapki (boleśnie dokładny opis).

Rusz troszkę głową i poskładaj to wszystko do kupy. Masz komplet informacji.
Z postów wynika, że linkowanie kernel32.lib masz już włączone (chyba, że coś pomieszałeś).

Swoją drogą przypuszczam, że problemem jest zbyt naiwny algorytm obliczania silnia. Jeśli masz obliczać silnię dla dużych wartości, to obsługa dużych liczb (takich z +50 cyframi) to już jest poważniejsze wyzwanie obliczeniowe i jest sens to mierzyć.
Jesteś pewien, że dobrze zrozumiałeś swoje zadanie?

0

Fragment z https://docs.microsoft.com/pl-pl/windows/desktop/SysInfo/acquiring-high-resolution-time-stamps :
// We now have the elapsed number of ticks, along with the
// number of ticks-per-second. We use these values
// to convert to the number of elapsed microseconds.
// To guard against loss-of-precision, we convert
// to microseconds before dividing by ticks-per-second.
//

ElapsedMicroseconds.QuadPart *= 1000000;

int main(void) {
  int a, wynik;
  LARGE_INTEGER ctr1 = 0, ctr2 = 0, freq = 0;
  double czas;

  printf("Podaj, ktory wyraz ciagu (silnia) chesz wpisac\nGdy podasz ujemna liczbe, funkcja zwroci 0\nPodales: ");
  scanf("%d", &a);
  QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
  QueryPerformanceCounter((LARGE_INTEGER *)&ctr1);

  wynik = silnia(a);

  QueryPerformanceCounter((LARGE_INTEGER *)&ctr2);
  czas = (double)(ctr2 - ctr1) * 1000000.0;
  czas = czas/freq;

  printf("Ten wyraz ciagu silnia ma wartosc %d\n", wynik);
  printf("Czas obliczen to: %lf", czas);
  return 0;
}

Mam parę pytań co do drugiego linku:

  1. U nich, elapsedMicroseconds jest typu LARGE_INTEGER, u mnie zmienna "czas" jest typu double, bo jakoś muszę pokazać ten czas (za pomocą specyfikatora %lf na przykład). Jak w takim razie pokazać tę wartość, skoro występuje w niej ten typ LARGE_INTEGER? W C++ nie trzeba używać tych specyfikatorów w cout, więc sprawa jest prostsza.
  2. https://support.microsoft.com/pl-pl/help/815668/how-to-use-the-queryperformancecounter-function-to-time-code-in-visual <- W tym przykładzie zmienne ctr1 i ctr2 są typu __int 64, a w tym acquiring high resolution stamps są typu LARGE_INTEGER. Jest jakaś różnica między nimi?
  3. "ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;" Rozumiem, że w C nie piszę tego członu ".QuadPart"?
  4. Co do samej składni QueryPerformanceFrequeny: "BOOL WINAPI QueryPerformanceFrequency(
    Out LARGE_INTEGER *lpFrequency);" . O co chodzi z tym Out? BOOL WINAPI to jeden ze wspomnianych typów __Int64/LARGE_INTEGER?

Wydaje mi się, że jestem coraz bliżej rozwiązania i być może problemem jest zły typ zmiennej czas. Tylko tutaj przechodzę do pytania 1.

1

LARGE_INTEGER to nic innego jak reprezentacja liczby w postaci bitowej gdzie wartość jest podzielona na starsze 4 bajty i młodsze 4 bajty
klik
tylko się nie przestrasz DWOR'a bo to tylko
typedef unsigned long DWORD;

1

Napisałeś silnia, które liczy dla bardzo dużych liczb?
Z tego wynika, że prosta naiwna silnia nadal jest za szybka by dało się ją bezpośrednio zmierzyć (pokrywa się to z moją estymatą).
Inna metoda to pomierzyć kilka (~100) wywołań tej funkcji, ale należy pamiętać, że kompilator może dużo zoptymalizować, więc proste wywołanie z tym samym argumentem nic nie da.

1 użytkowników online, w tym zalogowanych: 0, gości: 1