Sortowanie bąbelkowe z OpenMP

Sortowanie bąbelkowe z OpenMP
R9
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 12 lat
  • Postów:39
0

Witam. Chciałbym zrealizować sortowanie bąbelkowe dla ciągu liczb rzeczywistych z wykorzystaniem OpenMP. Jednak mam problem ze zrównolegleniem. Ponieważ nie zawsze zadziała poprawnie. Czy trzeba tutaj zrównoleglać drugiego fora też?

Mój kod:

Kopiuj
 #include <stdio.h>
#include "omp.h"

int main()
{
int n=10;
double X[10] = {0.4, -1.7, 2.2, 3.4, 2.2, -8.1, 9.2, -100, 99.01, 9};
int i, j;
double tmp;
int a=0;
omp_set_num_threads(4);

//for(a =0; a<n; a++)
//printf("%.2f ,", X[a]);
//printf("\n");

#pragma omp parallel for default(none) private(i,j,tmp) shared(n, X)
		for(i = 0; i< n; i++)
			for(j=0; j< (n-1-i); j++)
			{
				#pragma omp flush(X)
				if(X[j]>X[j+1])
				{
					tmp = X[j+1];
					X[j+1] = X[j];
					X[j] = tmp;
				}
			}


for (j = 0; j<n; j++)
printf("%.2f, ", X[j]);
printf("\n");


return 0;
}

02
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 8 lat
  • Postów:1176
0

W tym kodzie wenętrzny for jest urachamiany równolegle - co znaczy, ze w kilku wątkach próbujesz zamieniać elementy dzielonej tablicy. To oczywiście prowadzi do błędów.
Po co w ogóle chcesz zrównoleglac bubble sorta? To typowo sekwencyjny algorytm. Jeżeli chcesz sobie poćwiczyć OpenMP to już lepiej spróbuj zrównoleglić sortowanie przez scalanie.

edytowany 2x, ostatnio: 0x200x20
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:minuta
0
Kopiuj
                                #pragma omp flush(X)

Wiem że się czepiam, i że kompilatory to łykają, ale zgodnie ze standardem języka, powinno się pisać

Kopiuj
#                                pragma omp flush(X)

czyli # w pierwszej kolumnie, a dopiero potem może być odstęp.

edytowany 1x, ostatnio: Azarien
Endrju
To nie jest prawda. Można tak robić od 1989 roku i jest to całkowicie zgodne ze standardem (C11 - 6.10.2).
Azarien
jeśli tak, to mnie chyba okłamali.
Endrju
Nie tyle okłamali, co ta zasada jest bardzo stara i już nieaktualna.
R9
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 12 lat
  • Postów:39
0
0x200x20 napisał(a):

W tym kodzie wenętrzny for jest urachamiany równolegle - co znaczy, ze w kilku wątkach próbujesz zamieniać elementy dzielonej tablicy. To oczywiście prowadzi do błędów.
Po co w ogóle chcesz zrównoleglac bubble sorta? To typowo sekwencyjny algorytm. Jeżeli chcesz sobie poćwiczyć OpenMP to już lepiej spróbuj zrównoleglić sortowanie przez scalanie.

Próbuję się przed tym właśnie w jakiś sposób zabezpieczyć. Na przykład:

Kopiuj
#include <stdio.h>
#include "omp.h"

int main()
{
int n=10;
double X[10] = {0.4, -1.7, 2.2, 3.4, 2.2, -8.1, 9.2, -100, 99.01, 9};
int i, j;
double tmp;
int a=0;
omp_set_num_threads(4);

//for(a =0; a<n; a++)
//printf("%.2f ,", X[a]);
//printf("\n");

#pragma omp parallel for default(none) private(i,j,tmp) shared(n, X)
	for(i = 0; i< n; i++)
		for(j=0; j< (n-1-i); j++)
		{
			#pragma omp flush(X)
			if(X[j]>X[j+1])
			{
				#pragma omp critical
				{
					if(X[j]>X[j+1])
					{
						tmp = X[j+1];
						X[j+1] = X[j];
						X[j] = tmp;
					}
				}
			}
		}

for (j = 0; j<n; j++)
printf("%.2f, ", X[j]);
printf("\n");


return 0;
}

Jednak critical nie pomaga. Gdzieś widziałem rozwiązanie, że ten drugi for też jest "#pragma omp parallel for". Niemniej to również nie daje poprawnego wyniku.

Co do potrzeby zrównoleglania bubblesorta, to powiedzmy, że mam postawione takie zadanie, które muszę zrealizować. Na pewno można zaoszczędzić na złożoności dzięki OpenMP.

Z góry dziękuję pomocnym


edytowany 1x, ostatnio: razor91pl
02
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 8 lat
  • Postów:1176
1

Jeżeli chcesz to mozesz sobie zrobic cos takiego:

Kopiuj
#pragma omp parallel for private(i, j, tmp) shared(n, X)
for(i = 0; i< n; i++)
{
	#pragma omp critical
    for(j=0; j< n-1; j++)
    {
        if(X[j]>X[j+1])
        {
                tmp = X[j+1];
                X[j+1] = X[j];
                X[j] = tmp;
        }
    }
}

Tyle ze jest to calkowicie bezsensu bo tak na prawde prawde kod nie jest zrownoleglony (wewnetrzne petle wykonuja sie po kolei). Nie da sie zrownoleglic bubble sorta bez modyfikacji samego algorytmu - bubble sort jest po prostu sekwencyjny. Tu jest jakas zrownoleglona wersja: http://alecu.ase.ro/conferences/nat_conf_2005_ro_am.pdf - na twoim miejscu przepisal bym na C++ z OpenMP.

edytowany 2x, ostatnio: 0x200x20
R9
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 12 lat
  • Postów:39
0
0x200x20 napisał(a):

Jeżeli chcesz to mozesz sobie zrobic cos takiego:

Kopiuj
#pragma omp parallel for private(i, j, tmp) shared(n, X)
for(i = 0; i< n; i++)
{
	#pragma omp critical
    for(j=0; j< n-1; j++)
    {
        if(X[j]>X[j+1])
        {
                tmp = X[j+1];
                X[j+1] = X[j];
                X[j] = tmp;
        }
    }
}

Tyle ze jest to calkowicie bezsensu bo tak na prawde prawde kod nie jest zrownoleglony (wewnetrzne petle wykonuja sie po kolei). Nie da sie zrownoleglic bubble sorta bez modyfikacji samego algorytmu - bubble sort jest po prostu sekwencyjny. Tu jest jakas zrownoleglona wersja: http://alecu.ase.ro/conferences/nat_conf_2005_ro_am.pdf - na twoim miejscu przepisal bym na C++ z OpenMP.

Dziękuję za ten materiał. Powoli zaczynam rozumieć.
A czy takie rozwiązanie, gdzie parami dzielę między wątki dwa elementy ciągu ma sens? nie ma chyba możliwości brudnego zapisu, a powinno to przyspieszyć działanie programu?

Kopiuj
#include<stdio.h>
#include<omp.h>

#define N 13

int main()
{
	int i, j;
	double temp, tab[] = {1.1, 2.3, -1.2, 9.2, 8.1, 7.8, 6.4, 5.0, 4.1, -33.2, 2.7, 1.1, 0};
	for(i = 0; i < N; i++)
	{
		#pragma omp parallel for num_threads(4) private(temp)
		for (j = 0; j < N - 1; j += 2)
			if (tab[j] > tab[j+1])
			{
				temp = tab[j];
				tab[j] = tab[j+1];
				tab[j+1] = temp;
			}
		#pragma omp parallel for num_threads(4) private(temp)
		for (j = 1; j < N - 1; j += 2)
			if (tab[j] > tab[j+1])
			{
				temp = tab[j];
				tab[j] = tab[j+1];
				tab[j+1] = temp;
			}
	}
	for(i = 0; i < N; i++)
		printf("%.2f ", tab[i]);
	printf("\n");
}

02
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 8 lat
  • Postów:1176
1

Ogolnie nie ma sensu - nie otrzymasz w ten sposob posortowanego ciagu... chyba ze zastosujesz scalanie dwoch posortowanych ciagow w jeden posortowany ciag. A to jest zaczątek sortowania przez scalanie, ktore dobrze sie zrownolegla, ale ktore juz nie jest sortowaniem babelkowym.
Przeklepany algorytm z wczesniej wymienionego linku:

Kopiuj
#include <cstdio>
#include <omp.h>
#include <utility>
 
int main()
{
	static const int N = 10;
	double X[N] = {0.4, -1.7, 2.2, 3.4, 2.2, -8.1, 9.2, -100, 99.01, 9};


	for(int k = 0; k < N-1; k++)
	{
		if(k % 2 == 0)
		{
			for(int i = 0; i <= N/2-1; i++)
			{
				if(X[2*i] > X[2*i+1]) 
					std::swap(X[2*i], X[2*i+1]);
			}
		}
		else
		{
			for(int i = 0; i <= N/2-2; i++)
			{
				if(X[2*i+1] > X[2*i+2]) 
					std::swap(X[2*i+1], X[2*i+2]);
			}
		}
	}
 
	for (int j = 0; j<N; j++)
		std::printf("%.2f, ", X[j]);
 
	return 0;
}

Jedyne co musisz zrobić to zrownoleglic 2 wewnetrzne petle przy uzyciu OpenMP (banał). Działa to tak, że w parzystej iteracji sortujesz parzyste elementy i sąsiadów parzystych elementów, a w nieparzystej - nieparzyste elementy i ich sąsiadów.

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 16 godzin
0

Moim zdaniem kod z 20:08 ma szansę działać. Przynajmniej dla danych przykładowych działa: http://ideone.com/gpE5Mr
Jak ktoś ma kontrprzykład to niech zarzuci :P


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
R9
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 12 lat
  • Postów:39
0
Wibowit napisał(a):

Moim zdaniem kod z 20:08 ma szansę działać. Przynajmniej dla danych przykładowych działa: http://ideone.com/gpE5Mr
Jak ktoś ma kontrprzykład to niech zarzuci :P

Działa. Testowałem 1000 razy dla 1000000 liczb. Niemniej działa wolniej od sekwencyjnego :) Poprawiłem według wskazówek kolegi i wszystko śmiga z lepszą złożonością.


Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)