[C#] Błędne liczenie czasu wykonania


(mateusz-1991) #1

Witam,

 

Mam pewien problem z programem w C#. Napisałem sobie program liczący silnię z dużych liczb (przy użyciu BigInteger). Chciałem sobie zmierzyć czas wykonania programu. Użyłem różnych sposobów (stopwatch, DateTime), lecz każdorazowo mam błędny czas tzn. program wypisuje mi czas np.: 9 sekund, podczas gdy liczenie z stoperem w ręku zajęło 40 sekund. Wie ktoś co może powodować wymieniony tu problem?

 

Kod:

DateTime start = DateTime.Now;
BigInteger resultF = silnia(n);
DateTime stop = DateTime.Now;
TimeSpan fullTime = stop - start;
Console.WriteLine("Wynik: " + resultF + "\nCzas pracy: " + fullTime.Seconds + " sekund");

(kalitt) #2

Spróbuj liczyć czas w innym wątku. Być może po prostu pojedynczy wątek jest zbyt mocno obciążony


(Fiołek) #3

@ kalitt - i niby jak “liczenie” czasu zrealizować w osobnym wątku? Obciążenie wątku nie ma najmniejszego wpływu na to(bo odczyt aktualnego czasu systemowego to wywołanie odpowiedniej funkcji Win32Api, które (w większości przypadków) są na to odporne).

 

@topic - zacznijmy od tego, że licząc czas ze stoperem w ręku liczysz nie tylko czas obliczeń, ale też np. czas startu.

Komputer nie kłamie, jeśli program mówi, że obliczenia zajęły 9s, to tyle zajęły(pod warunkiem, że prawidłowo liczysz). Warto też zwrócić uwagę na to, że TimeSpan.Seconds nie zwraca całkowitej ilości sekund, tylko seconds component(składową sekundową?) czasu w formacie hh:mm:ss (czyli np. dla 1m i 20 s da to wynik 20, nie 80). Wydaje mi się, że bardziej interesująca jest właściwość TimeSpan.TotalSeconds, która to zwraca całkowity czas w sekundach(czyli dla w/w przykładu - 80).


(mateusz-1991) #4

Stoper nacisnąłem w momencie wprowadzenia liczby z której ma być liczona silnia (rozpoznałem to m.in. po wzroście obciążenia generowanego przez proces programu). Cały kod:

using System;
using System.Numerics;

namespace Silnia
{
	class Program
	{
		private static BigInteger silnia(int i)
		{
			BigInteger result = 1;
			for (int x=1; x<=i; x++)
			{
				result *= x;
			}
			return result;
		}
		
		public static void Main(string[] args)
		{
			Console.Write("Wprowadź liczbę, której silnię pragniesz policzyć: ");
			int n = int.Parse(Console.ReadLine());
			DateTime start = DateTime.Now;
			BigInteger resultF = silnia(n);
			DateTime stop = DateTime.Now;
			TimeSpan fullTime = stop - start;
			Console.WriteLine("Wynik: " + resultF + "\nCzas pracy: " + fullTime.Seconds + " sekund");
			Console.ReadKey();
		}
	}
}

Coś jest tu źle? Wydaje mi się, że przekazanie liczby do funkcji nie powinno zająć więcej niż sekunda… Powiem jeszcze, że ten sam problem objawia się na innych maszynach. Spróbowałem to rozdzielić na minuty, sekundy, ale dalej to samo. Jak użyję np.: TotalSeconds to mam liczbę typu double, ale dalej błędną.

 

@Edit

Silnię oczywiście liczy poprawnie.


(Lukasz Pyrzyk) #5

Wykorzystaj klasę Stopwatch


(mateusz-1991) #6

Korzystałem z stopwatcha z pakietu Diagnostics i to samo. Kombinowałem z różnymi opcjami zarówno dla stopwatcha, jak i DateTime’a i dalej coś nie liczy poprawnie. Programy w Javie dobrze mierzą czas. Tylko ten C# coś nie halo. Szukałem rozwiązań w dokumentacji Microsoftu, jak i z innych for typu zagraniczne “przepełniony stos”, ale rozwiązań brak…


(Fiołek) #7

Już wiem, czemu uważasz, że źle czas liczy. Niestety jesteś w błędzie. Czas obliczeń liczy dobrze, ale problemem jest konwersja BigIntegera na ciąg znaków. Proof(wersja ze Stopwatchem, bo od tego on jest): http://pastebin.com/W5NePeYd


(mateusz-1991) #8

Hmm… Ewidentnie mój błąd. Wyszedłem z błędnego założenia co do wypisywania i BigInteger. Liczyłem poprawkę na samo drukowanie na ekranie, ale nie przewidziałem czasu potrzebnego na konwersję. Człowiek całe życie się uczy… mimo tych wielu lat programowania.

Dziękuję za pomoc.