szybkosc mnozenia zmiennych typu float

0

Witam,

Mam do napisania funkcje obliczajaca srednia i wariancje.
O ile przy sredniej sprawa jest banalna, o tyle mam pytanie nt. szybkosci
obliczania wariancji w przypadku duzej ilosci danych. Kod zamieszczam ponizej:

// definicja funkcji narzucona przez wykladowce
void calcMeanVar(float *data, int size, float *mean, float *var) 
{
	float sum = 0, * ptr = data; // ustaw ptr na poczatek tablicy danych
	for (int i = 0; i < size; i++, ptr++)
		sum = *ptr;
	*mean = sum / nReps;

	sum = 0;
	float tmp;
	ptr = data; // reset ptr
	for (i = 0; i < size; i++, ptr++) { // min dla size jest 2 aby policzyc wariancje
		tmp = *ptr - *mean;

	/* ktory kod bedzie szybszy jesli w ogole gdy size >= 10E5 */
		sum += tmp * tmp;
		// tmp *= tmp;
		// sum += tmp;
	}
	*var = sum / (size - 1);
}

Pytanie w komentarzu kodu.

Dzieki za zainteresowanie i info,
mossy

1

Bez optymalizacji ten w komentarzach będzie wydajniejszy (nie wymaga użycia tymczasowego rejestru), natomiast w każdym sensownym kompilatorze to będzie to samo.

Btw gdy size >= 10E5 co to ma do rzeczy?

1
    for (int i = 0; i < size; i++, ptr++)
        sum = *ptr;

Really? Powinno być sum += *ptr.

Co do pytania głównego: myślę, że w 99%+ przypadków różnica wydajności wyniesie 0. Nawet jeśli w jednej postaci będzie użyty jeden rejestr więcej, to i tak będzie to rejestr zmiennoprzecinkowy, a te są odrębnym zbiorem niż rejestry stałoprzecinkowe w chyba wszystkich architekturach CPU. Z faktu iż rejestry zmiennoprzecinkowe nie są używane do indeksowania pamięci, a dodatkowo wolna pula rejestrów zmiennoprzecinkowych jest większa niż pula stałoprzecinkowych to trochę trudniej z nimi przedobrzyć.

x87 ma 8 rejestrów, SSE też, a tutaj zmiennych zmiennoprzecinkowych są w zasadzie dwie: sum i tmp. Nawet jeśli przyjmie się kilka więcej na wyniki częściowe to i tak raczej nie wyjdzie poza 8. Gdyby wyszło to wtedy trzeba częściej przerzucać dane między rejestrami, a pamięcią i to zajmuje trochę czasu.

0

co do kodu, to bylo 'typo', wychwycilem to juz wczesniej w programie :)

poza tym dzieki za szczegolowe info

2

Generalnie wszystko zależy od kompilatora i jego efektywnej (bo może zostać ograniczona parametrami) "mocy optymalizacyjnej".
Teoretycznie poniższe powinno być szybsze dla maksymalnej ilości przypadków:

inline float sqr(float x) { return x*x; }

void calcMeanVar(float *data,size_t size, float *mean, float *var) 
  {
   float sum=0,*end=data+size;
   for(float *ptr=data;ptr<end;sum+=*(ptr++)) {}
   *mean=sum/size;
   sum=0;
   for(float *ptr=data;ptr<end;sum+=sqr(*(ptr++)-*mean)) {}
   *var=sum/(size-1);
  }

Tak czy owak radziłbym rozdzielenie na dwie funkcji: calcMean, calcVar ponieważ są niezależne.

0

Owszem sa niezalezne, ale jak pisalem w pierwszym komentarzu w kodzie, jest to narzucona definicja od wykladowcy. A ze jest to element wiekszej symulacji, wiec dla kazdej symulacji lepiej jest wywolac jedna fukcje, niz dwie lub trzy oddzielne.

Ponadto, czy wywolanie sqr, w tym przypadku, nie spowalnia ??

1

Ponadto, czy wywolanie sqr, w tym przypadku, nie spowalnia ??

Przy włączonej optymalizacji to bez znaczenia.

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