Zum Inhalt springen

Schlitzauge

Mitglieder
  • Gesamte Inhalte

    40
  • Benutzer seit

  • Letzter Besuch

  1. Naja, zumindest mächtiger als jeden anderen den ich kenne (Pascal, C#, Fortran, etc.). Ganz im Ernst? Geht das, also so, dass man das direkt dann in C/C++ nutzen kann (also mit jedem C/C++-kompatiblen Compiler)??? Da würde ich gerne mal ein Beispiel sehen. Wüsste jetzt nicht, wonach ich da googlen soll...
  2. Nein, nein, da habe ich mich etwas missverständlich ausgedrückt. Ich meinte damit genau den Export von Symbolen und die Aufrufkonvention. Aber: "so compilliert, dass der Code aus C benutzbar ist", wage ich mal zu bezweifeln. Oder ließe sich damit C++-Code (so mit class etc.) dann auch mit einem C-Compiler übersetzen? Ich glaube ja nicht. Nun jut, dann verwerfe ich gleich mal wieder den Gedanke mit "extern "irgendwas""...
  3. Hab ich gerade in meiner Selbsterkenntnis selber bemerkt: Das habe ich mir schon fast gedacht. Schade, wäre ein ziemlich mächtiger Präprozessor gewesen und würde mir viel Arbeit bei meinem Vorhaben ersparen. Da werde ich um externe Tools wohl nicht drumherum kommen... Falls doch noch wer Ideen oder vermeintliche "Unlösungen" dazu finden sollte, bitte... Ich hab jetzt zumindets einige Ansätze, die ich weiterverfolgen werde... Thx, Grüße Schlitzauge
  4. Ja, schon, glaube ich zumindest, lasse mich aber auch gerne eines besseren belehren. Das "extern "C""{} dient meines Wissens nach dazu, dass solcher Code, insb. Funktionsdeklarationen vom C++-Compiler wie von einem C-Compiler behandelt wird (Stichwort: name mangeling bei Funktionsdeklarationen). Da es zum Standard gehört, ist es wohl also ne Frage des Compilers. Wollte ich z.B. ein: extern "f95" implementieren, ginge das also nur über eine Anpassung des Compilers, korrekt? Gibt es da sonst noch ne Möglichkeit, sowas mit Sprachmitteln zu realisieren (ich glaube ja eher nicht)?
  5. #include <iostream> using namespace std; int main(int argc, char* argv[]) { #define int float int test1 = 5.458; cout << test1 << endl; #define int int int test2 = 5.458; cout << test2; getchar(); return 0; } Dein Hinweis war top. Ig werd bekloppt, dass funktioniert ja wirklich. Komisch. Ich hatte es irgendwie die ganze Zeit in Erinnerung, dass das nicht geht bzw. der Compiler seinen Dienst quitiert, weil bereits reservierte Schlüsselwörter manipuliert werden. Vlt. liegts auch einfach nur daran, dass man sowas eigentlich nicht macht und ich das mal so gelernt habe. Ok, wieder was dazugelernt. EDIT: Ok, mit typedefs kann man sowas aber leider nicht machen. Richtig, deshalb geht mein Gedanke auch in Richtung Bereichskapselung a´la OpenMP, dann sollte auch nichts mehr knallen. Na perfekt, fehlt nur noch die Möglichkeit Sonderzeichen zu redefinieren, halt sowas: #define := = #define ^ * Hier getestet quitiert der Compiler aber den Vorgang, da kein Bezeichner: Gibts da nicht Möglichkeiten???
  6. Sowas wäre mir auch recht, funktioniert gut mit OpenMP. Bei CUDA-C geht das ganze noch einen Schritt weiter, indem es dort einfach spezielle Schlüsselwörter oder Syntaxänderungen (die sich aber hervorragend in die C/C++-Syntax einpasst) gibt und der nvcc automatisch CUDA-spezifischen Code und C/C++-Code trennt, übersetzt und beide OBJ´s gegeneinander linkt (scheint mir aber eine Compiler-Änderung bzw. externes Tool zu sein, als syntaktisch gelöst). Aber wie lässt sich sowas umsetzen, ohne auf externe Tools zurückzugreifen oder den Compiler zu verändern??? Und gemäß dem Fall, sowas wie eigene Direktiven a´la OpenMP schaffen zu wollen. Wie kann man eigene Direktiven deklarieren / implementieren, sodass jeder Compiler (so die üblichen) damit umgehen können? Ist es im Fall von OpenMP nicht so, dass hierfür dann auch ein OpenMP-kompatibler Compiler benötigt wird? Hier wäre dann ja wieder eine Compileranpassung gefragt. Wäre ja schön, wenn die diversen Programmiersprachen entsprechende Inline-Konstrukte ähnlich OpenMP besitzen würden, hier halt nur zur gezielten Inline-Verwendung von mehreren Sprachen. In etwa solch ein Pragma (z.B. in C/C++: #pragma language <Name> [optionale Parameter...] { } So könnte man sich das ständige Schreiben von Wrappern sparen. Ich finde ja .NET und LLVM hier zwei andere interessante Lösungsansätze system- & programmiersprachenunabhängig zu programmieren. Mich interessieren hier aber primär die Möglichkeiten mit C/C++-eigenen Mitteln. Gilt vlt. auch als Herausforderung für andere, das vermeintlich Unmachbare, machbar zu machen. Achso, heißt das also, dass das "extern "C"" nicht zum Sprachstandard (gemessen an Feature-Unterstützung der prominentesten Compiler) von C++ gehört? Und wenn ich ähnliche Konstrukte implementieren möchte, z.B. "extern "f95"", geht das nur über eine Compiler-Anpassung, also nix mit syntaktische Erweiterung im Sinne von Bibliotheken? Mein eigentlicher Hauptgrund auf Wrapper-Lösungen zu verzichten, liegt eigentlich nur darin begründet: a.) herauszufinden, ob es nicht doch noch andere Möglichkeiten gibt (rein aus Interesse und vielmehr eine Machbarkeitsstudie), und b.) weil Kapselungen im Sinne von Wrapper-Methoden zusätzlichen Overhead erzeugen. Ich bin vielmehr an einer Inline-Lösung interessiert, wo beim Compilieren eine x-beliebige Sprache zunächst in C/C++ übersetzt (daher auch der Gedanke mit dem #define zur Über- bzw. Ersetzung von nicht-konformer C/C++-Syntax in konforme C/C++-Syntax) und dann erst der eigentliche Compile-Vorgang ausgeführt wird. Natürlich ist mir schon bewusst, dass einige Dinge nicht gehen werden, aber die meisten Programmiersprachen sind von der Funktionalität her nunmal kompatibel zueinander bzw. lassen sich kompatibel zueinander einsetzen. Genau hier würde ich gerne ansetzen, eben die "möglichen" Funktionalitäten syntaktisch nach C/C++ zu integrieren / migrieren (ohne Einsatz von externen Tools). Wie gesagt, das soll erstmal eine Art Machbarkeitsstudie und Ideensammlung sein. Falls wer dazu Lösungen, Lösungsansätze oder weitere Ideen hat, bitte.. MfG Schlitzauge
  7. Es ist vielmehr ein Machbarkeitsexperiment, ob da je was ernsthaftes drauß wird, wohl eher nicht. Mich interessieren einfach mal die Grenzen und ob man nicht doch die eine oder andere Grenze sprengen bzw. erweitern könnte. Falls wer Ideen dazu hat, bitte... Ja? Hab ich ja nicht behauptet. Wie würde sowas aussehen? Ich kann mit #define und typedefs "neue" Typen festlegen oder bestehende "umbenennen", aber dann eben nur andersgeschrieben. Ich wollte gerne sowas wie eine Typenerweiterung von int und Co. praktizieren. Also dass man weiterhin entsprechend der C/C++-Syntax eine int-Variable anlegen kann, z.B.: int var1 = 0; var1 dann aber eben nicht nur eine int-Variable ist, sondern ein struct / class mit gleichen Typ-Namen int. Wenn das irgendwie gehen sollte, wäre ich sehr daran interessiert, thx.
  8. Sers, Hab da ein neues Projekt am laufen und bzgl. #defines eine Frage. Ok, bereits reservierte Wörter zu redefinieren scheint wirklich nicht zu gehen. Was ich aber gerne machen würde ist, Zeichen und Zeichenketten zu definieren. Also etwa #define ^ * oder #define := = oder auch ganze Zeichenketten: #define "DO i = 1, 4711 {...} ENDDO" "for(i=1;i<=4711;++i){{...}}" Es heißt ja, dass der Präprozessor bzw. die Präprozessordirektive #define nichts weiteres macht, als entsprechende Definitionen vor dem eigentlichen Compilieren im Quelltext zu ersetzen / übersetzen. Ich suche eine Möglichkeit, sich hier nicht nur auf klassische Symbolwörter (also Wörter nur aus Buchstaben und Zahlen) zu beschränken. Geht das irgendwie, den #define-Befehl oder andere Mittel von C/C++ zum übersetzen von Text zu verwenden? Auf Codegeneratoren und / oder Übersetzer-Tools möchte ich nicht zurückgreifen, sondern das Ganze allein mit C/C++-Mitteln realisieren, sodass meine Quelltexte dann auch entsprechend mit beliebigen C/C++-Compilern übersetzt werden können. Und, gibt es nicht doch eine Möglichkeit bereits reservierte Wörter, wie "int" zu redefinieren?, etwa: struct|class INT { public: int var; }; #define int INT() Damit könnte ich aus skalaren Typen, wie int z.B. Struktur- bzw. Klassenobjekte machen, ähnlich wie in C#. Grüße Schlitzauge
  9. Das war keine Aussage, sondern eine Frage bzw. Hinterfragung und sorry, dass war aber wortwörtliche Deine Aussage: Falls ich das falsch verstanden haben sollte, bitte ich um Aufklärung. Ein Vektor ist allgemein gesagt, eine Menge / Liste von Zahlen (Skalaren), sowie eine Verschiebung im Vektorraum. Ein Vektor kann selbst wiederum ein Träger von Vektoren sein, etwa ein 2D-Vektor. Ein 2D-Vektor besitzt immer ein Zahlenpaar (x, y), wobei jede Komponente ein einfacher 1D-Vektor (Skalar) ist. Bei 3D-Vektoren spricht man hingegen von einem Tripple bzw. von drei Komponenten (x,y,z), usw. Raum: Mit geographischen Bezug, im Sinne des euklidischer Raum und des kartesischen Koordinatensystems, beschreibt ein Vektor eine Verschiebung einer n-dimensionalen topologischen Struktur und seine Komponenten die kartesischen Koordinaten. Hm, schnief.:confused: Es hilft mir nicht weiter, wenn man mich auf Erkenntnisse aufmerksam macht, die ich für mich schon selber entdeckt habe. Mathematisch ist diese Materie für mich kein Problem, aber irgendwas Grundlegendes tue ich anscheinend beim programmiertechnischen Umsetzen verwechseln, weshalb für mich Missverständnisse => Unklarheiten aufkommen. Ich würde es eventuell (100% Sicherheit gibt es nie) besser verstehen, wenn man mir konkret sagen würde, was nun richtig ist und was falsch und wenn falsch, warum. Wenn die Umsetzung mittels eindimensionaler Arrays und auch mittels mehrdimensionaler Arrays SO einfach sein soll, warum dann nicht einfach mal einen Beispielcode posten. Ungeachtet dessen, ob ich es verstehe oder nicht, hätte ich wenigstens etwas, was richtig ist und was ich analysieren könnte und ggfl. bei Unklarheit nochmals hinterfragen kann. Tutorials, Nachschlagewerke und Bücher habe ich nun sehr viele durchforstet. Wenn ich die Antwort auf meine Frage(n) dort gefunden hätte, würde ich dann noch hier nachfragen??? Es ist aber keineswegs so, dass ich hier nach Fertiglösungen suche, so nach der Devise: "brauche was, macht mal!", sondern dass ich mich nun sehr lange mit der Materie auseinandersetze und viel ausprobiere (unter Aneignung theoretischen Wissens). Manchmal kann dann trotzdem irgendwas noch unklar erscheinen. Ist ein Forum nicht dazu da, jemanden / andere um Hilfe zu bitten? Ich verlange ja nicht, mir sämtlichen Stoff vorzugaukeln, sondern bitte lediglich darum, mir bei dem einen konkreten Fall zu helfen. Ich wäre bzw. bin sehr dankbar für jede Hilfestellung, Lösungen, Lösungsansätze und Hinweise. Grüße Schlitzauge :confused:
  10. Ah ok. Verstehe ich das richtig, dass ein Array von 1000 Elementen (array[1000]) einem 1000-dimensionalen mathematischen Raum gleichkommt? Bzw. ein dreikomponentiges Array (array[3]) einem 3D-Raum? Naja, ich möchte nicht irgendwas krampfhaft umsetzen, sondern lediglich Folgendes: a(x1,y1) + b(x2,y2) = c(x1+x2,y1+y2) = c(x3,y3) Wie ich bereits mehrfach erwähnt habe, also die Vektoraddition mehrkomponentiger Vektoren (in den Beispielen also mit 2D-Vektoren / zweikomponentiger Vektoren). Wie ich das mittels struct umsetze, ist klar, funktioniert auch bestens. Ich wollte das aber gerne mal mittels einfacher Arrays und einmal mittels mehrdimensionaler Arrays umsetzen, ich weiß nur nicht wie. Könnte da mal jemand nen Beispiel-Code geben oder über meine zwei, drei Beispiele drüber gucken, vlt. hab ich ja bereits schon eine Lösung mittels Arrays umgesetzt. Mir ist schon klar, dass wir hier im C++-Forum sind und nicht im Mathe-Forum. Zum Code-spezifischen Teil, insb. zum OpenMP-spezifischen, komme ich erst noch. Vorher hätte ich das Bisherige aber erstmal gerne abgeklärt. Da das unmittelbar mit meinem eigentlichen Anliegen zu tun hat, wollte ich deshalb nicht gleich zwei getrennte Threads aufmachen.
  11. Dazu komme ich erst noch. Ja, dass gilt aber nur, wenn das Arrays dynamisch angelegt ist / wird. In meinem Fall hab ich es erstmal statisch angelegt. Ich möchte erstmal mit zweikomponentigen mathematischen Vektoren rechnen (x1+x2,y1+y2), es ist also eine festgelegte Vorgabe. Dazu bietet sich meine Lösung mit meinem struct-Datentyp auch entsprechend an. Nun würde ich aber mal gerne wissen, wie ich das rein mittels Arrays realisieren kann? Dazu habe ich mal einen Versuch unternommen: 2DVecAdd64_3.cpp const uint64_t NVdim1 = 400000000ULL, NVdim2 = 400000000ULL; //NVdim1 = x (col) //NVdim2 = y (row) uint64_t a[NVdim1][NVdim2] = {{0ULL}}, \ b[NVdim1][NVdim2] = {{0ULL}}, \ c[NVdim1][NVdim2] = {{0ULL}}; //serielle Variante: for(uint64_t i=0ULL;i<NVdim1;++i) { for(uint64_t j=0ULL;j<NVdim2;++j) { c[i][j] = a[i][j] + b[i][j]; } } omp_set_nested(2); //parallele Variante: #pragma omp parallel default(none) shared(std::cout, a, b, c) { #pragma omp flush #pragma omp for collapse(2) schedule(static) for(uint64_t i=0ULL;i<NVdim1;++i) { for(uint64_t j=0ULL;j<NVdim2;++j) { c[i][j] = a[i][j] + b[i][j]; } } }Nur bin ich mir jetzt unsicher, ob ich auch genau das Gleiche wie beschrieben (x1+x2,y1+y2) realisiere. Wenn ja, warum, wenn nein, warum nicht und wie müsste es denn ausschauen? Konkret gefragt, würde ich gerne wissen, wie denn meine struct-Lösung mit Arrays zu realisieren ist? Mir schweben da so einige Gedanken durch den Kopf: a.) 1D-Zeiger-Array von zweikomponentigen Arrays, also: Zweikomponentiges Array (2D-Vektor): array[2]; und davon halt ein Array für n 2D-Vektoren (bei mir stellvertretend durch a, b und c) anlegen. b.) Mittels mehrdimensionalem Array: 2DArray[x][y]; halt so, wie ich es bereits umgesetzt habe. Ich sehe da nur nicht, weshalb dort jeweils die Komponenten (x1+x2,y1+y2) miteinander addiert werden? Für mich sehe ich da nur eine skalare Addition, also das gleiche wie bei meinem ersten 1DVecAdd64.cpp-Prog von ganz oben. Ich verwechsle da anscheinend etwas zwischen der Dimension eines Arrays und der Dimension eines mathematischen Raumes. Da ich dazu noch nicht allzu viel Erfahrung habe, wäre ich für jeden Erklärungsversuch sehr dankbar. Mathematisch kann ich das alles, es hapert vom Verständnis her aber irgendwie bei der programmiertechnischen Umsetzung (also was mehrdimensionale Arrays angeht). Belesen hab ich mich bereits ausführlich genug: Tutorials, Bücher, etc., doch irgendwie werde ich nicht schlauer daraus. Deshalb frage ich nun hier nach. Gut möglich dass ich mit meinen Vermutungen bereits richtig liege, vlt. auch nicht. Ich bräuchte da mal jemanden, der mir nen Tritt verpasst. Grüße Schlitzauge :)
  12. Hi COM, also Parallelisieren mittels OpenMP funktioniert mittlerweile wunderbar. Wie das Addieren, Subtrahieren, Multiplizieren und Dividieren mit Vektoren bzw. Matrizen funktioniert ist mir auch bewusst (also mathematisch). Ich glaube auch, dass ich eine erfolgreiche Vektor- bzw. auch Matrix-Addition programmiert habe, soweit so gut. Ich habe allerdings gerade ein Verständnisproblem zwischen Arrays, Vektoren und Matrizen. Hier erstmal der Code einer stinknormalen 1D-Vektoraddition (Skalare Addition): 1DVecAdd64.cpp: const uint64_t NumValues = 800000000ULL; uint64_t a[NumValues] = {0ULL}, \ b[NumValues] = {0ULL}, \ c[NumValues] = {0ULL}; //serielle Variante: for(uint64_t i=0ULL;i<NumValues;++i) { c[i] = a[i] + b[i]; } //parallele Variante: #pragma omp parallel default(none) shared(std::cout, a, b, c) { #pragma omp flush #pragma omp for schedule(static) for(uint64_t j=0ULL;j<NumValues;++j) { c[j] = a[j] + b[j]; } } Funktioniert soweit auch wunderbar. Nun wollte ich aber mal in weitere Dimensionen vordringen, sprich 2D, 3D und 4D. Doch jetzt hab ich das Problem den Sinn und Zweck von mehrdimensionalen Arrays zu verstehen. Dazu mal ein Bsp.-Programm, wie ich eine 2D-Vektoraddition umgesetzt habe: 2DVecAdd64_1.cpp: const uint64_t NVdim1 = 400000000ULL, NVdim2 = 400000000ULL; //NVdim1: x (col) //NVdim2: y (row) uint64_t a[NVdim1][NVdim2] = {{0ULL}}, \ b[NVdim1][NVdim2] = {{0ULL}}, \ c[NVdim1][NVdim2] = {{0ULL}}; //serielle Variante: for(uint64_t i=0ULL;i<NVdim1;++i) { for(uint64_t j=0ULL;j<NVdim2;++j) { c[i][j] = a[i][j] + b[i][j]; } } //parallele Variante: #pragma omp parallel default(none) shared(std::cout, a, b, c) { #pragma omp flush #pragma omp for schedule(static) for(uint64_t i=0ULL;i<NVdim1;++i) { for(uint64_t j=0ULL;j<NVdim2;++j) { c[i][j] = a[i][j] + b[i][j]; } } } Was ist da der Unterschied zu vorher, also zur 1D-Variante? Für mich passiert hier genau das selbe: Skalare Additionen, nur liegen hier die Skalare (Array-Elemente) nicht mehr in einem 1D-Array, sondern in einem 2D-Array vor. Tatsache ist aber, dass über die Indizes jeweils immer nur eine normale Variable (Skalar) angesteuert wird, letztendlich also das gleiche passiert, wie im obigen Programm 1DVecAdd64. Was ich aber möchte ist eine klassische 2D-Vektoraddition (also eine Addition von zweikomponentigen Vektoren der Form v_n(x,y)). Ich möchte also folgendes damit berechnen können: v1(x1,y1) + v2(x2,y2) = v3(x1+x2,y1+y2) = v3(x3,y3) Bsp.: v1(5,7) + v2(2,3) = v3(5+2,7+3) = v3(7,10) Also die komponentenweise Addition. Ich sehe in meinem 2DVecAdd64_1-Prog aber nur die gleiche Berechnung wie im 1DVecAdd64-Prog, eine Addition von Skalaren. Weshalb mich das verwirrt?: Gerechnet wird stets nur mit Skalaren (1D-Vektoren), was den einzelnen Komponenten mehrkomponentiger (mehrdimensionaler) Vektoren entspricht. Ob ich mir jetzt ein eindimensionales Array hernehme: 1DArray[25]; oder ein zweidimensionales Array: 2DArray[5][5]; ist doch egal. Das sind in meinen Augen immer noch die gleichen Daten(mengen), lediglich etwas anders angeordnet und nun anders adressierbar. Gerechnet wird beim 2DVecAdd64_1-Prog letztenendes so: A_ArrayElement+B_ArrayElement = C_ArrayElement; Der Unterschied zwischen beiden Progs ist einfach nur die Art der Adressierung der Elemente (beim 1D-Prog gibt es jeweils nur einfache Indize, beim 2D-Prog halt zweifache Indize, schlussendlich wird aber jeweils immer nur ein Element (Skalar) angesprochen). Damit realisiere ich aber nicht das, was ich mir vorgestellt habe (glaube ich zumindest). Also habe ich es mal mittels eigenem Datentyp realisiert: 2DVecAdd64_2.cpp: struct V2D //2D-Vektor { public: uint64_t x, y; V2D(uint64_t X = 0ULL, uint64_t Y = 0ULL):x(X),y(Y){} ~V2D(){}; }; const uint64_t Num2DVecs = 400000000ULL; //Anzahl 2D-Vektoren struct V2D a[Num2DVecs], \ b[Num2DVecs], \ c[Num2DVecs]; //serielle Variante: for(uint64_t i=0ULL;i<Num2DVecs;++i) { c[i].x = a[i].x + b[i].x; c[i].y = a[i].y + b[i].y; } //parallele Variante: #pragma omp parallel default(none) shared(std::cout, a, b, c) { #pragma omp flush #pragma omp for schedule(static) for(uint64_t j=0ULL;j<Num2DVecs;++j) { c[j].x = a[j].x + b[j].x; c[j].y = a[j].y + b[j].y; } } Damit kann ich genau das realisieren / so rechnen, wie eben beschrieben. Jetzt könnte ich das für 3D und 4D so weiter machen, doch irgendwie werde ich nicht daraus schlau. Meine Frage ist nun, was richtig ist, um mit 2D-Vektoren (Vektor mit zwei Komponenten x und y) zu rechnen? (und warum). Ich meine, die Lösung mit eigenem Datentyp funktioniert und ist richtig. Doch wie müsste die Lösung aussehen, wenn ich das ausschließlich mit klassischen Arrays umsetzen möchte? Um es nochmal deutlich zu machen: ich möchte keine 1D-Vektor/Skalar-Addition: a+b=c , sondern eine 2D-Vektor-Addition (wo also jeweils einzeln die [x,y] Komponenten zweier solcher 2D-Vektoren zu Ergebniskomponenten eines 2D-Ergebnisvektors errechnet werden): v1(x1,y1) + v2(x2,y2) = v3(x1+x2,y1+y2) = v3(x3,y3) Ich habe folgendes versucht: 2DVecAdd64_3.cpp const uint64_t NVdim1 = 400000000ULL, NVdim2 = 400000000ULL; //NVdim1 = x (col) //NVdim2 = y (row) uint64_t a[NVdim1][NVdim2] = {{0ULL}}, \ b[NVdim1][NVdim2] = {{0ULL}}, \ c[NVdim1][NVdim2] = {{0ULL}}; //serielle Variante: for(uint64_t i=0ULL;i<NVdim1;++i) { for(uint64_t j=0ULL;j<NVdim2;++j) { c[i][j] = a[i][j] + b[i][j]; } } omp_set_nested(2); //parallele Variante: #pragma omp parallel default(none) shared(std::cout, a, b, c) { #pragma omp flush #pragma omp for collapse(2) schedule(static) for(uint64_t i=0ULL;i<NVdim1;++i) { for(uint64_t j=0ULL;j<NVdim2;++j) { c[i][j] = a[i][j] + b[i][j]; } } } Der gleiche Fall wieder. Was bringt mir das, wenn doch nur wieder Skalare miteinander addiert werden??? Meine Vermutung ist ja, dass ich etwas Grundlegendes verwechsle. Mittels Array kann man einen 2D-Vektor (zwei Komponenten) wie folgt darstellen: array[2]; wobei das array[] der Vektor ist und das Element mit Index 0 (array[0]) die x-Komponente und das Element mit Index 1 die y-Komponente. An sich liegen diese Komponenten aber erst einmal gleichwertig hintereinander. Wäre dann ein zweidimensionales Array: array2D[2][2]quasi zwei solcher Vektoren? Liegt es dann an mir / am Programmierer, jeweils die richtigen Datenelemente als x- und y-Komponenten zu interpretieren (etwa bei der Ausgabe oder beim Algorithmieren)? Das würde dann auch einiges erklären, wobei mir der Weg mittels struct dann doch optisch ansprechender und verständlicher erscheint. Ich danke vielmals im Voraus. Grüße Schlitzauge
  13. Sollte nur der Übersicht dienen. Damit wollt ich nur noch mal herauskristallisieren, was mir im Moment am wichtigsten ist. Aber ich weiß schon, was de meinst. Ich weiß, hab das ja und die ausführliche Doku dazu, 8x bzgl. meines Problem´s durchgeschaut. Es war lediglich eine Bitte, kein Muss. Da es sowieso nur ein Beispiel-Code sein soll und kein "übernehmt ma meine Aufgaben", ist das nicht soooo wichtig. Ich selber bin die ganze Zeit am Probieren. Faul bin ich da gewiss nicht. Das ist mir schon bewusst, dass in diesem Fall der Wertebereich überschritten werden kann bzw. wird. Das trifft aber auf mein Beispiel nicht zu, da die Iterationen fleißig auf alle Threads verteilt werden und am Ende zu einem reduziert werden, indem die Teilergebnisse zusammenaddiert werden. Ich lasse zwar in meinem Beispiel nicht die Zählvariable zu Einem reduzieren, aber eine separate Variable, die lediglich wertmäßig die Größe der Zählvariablen annimmt. Bzgl. des Pseudocode von Dir. Der würde in C/C++ mit OpenMP doch so ausschauen: unsigned char x = 0; #pragma omp parallel for reduction(x) for(int i = 0;i<omp_get_num_threads();i++) { x= 253; } , richtig? Grüße Schlitzauge :):)
  14. Wollte ich auch gar nicht. Aber bei dem Beispiel wird quasi das selbe Prinzip angewandt wie bei meinem, bloß mit reduction(&&: is_prime). Warum sollte dort dann ein Nutzen von Parallelität sein, wenn keiner bei meinem Beispiel greift? Dann seh ich es nicht. Hab mir diese jetzt schon 8x etwas ausführlicher angeschaut. Kann mir nicht einfach mal jemand ein kleines Beispiel für paralleles Hochzählen schreiben. Mit Code vor meiner Nase, kann ich so etwas wesentlich besser nachvollziehen. Wenns geht, bitte aber kein Pseudocode, da ich damit noch nicht so viel zu tun hatte. Direkte C/C++-Syntax sagt mir da schon mehr zu. Doch auch andere Beispiele von anderen Seiten verwenden genau das Gleiche Prinzip wie ich oben und behaupten trotzdem, dass dabei ein Nutzen von Parallelität greift. Hier nur mal zwei Beispiele: Quelle 1 (Abschnitt Akkumulation): OpenMP Code: int accumulate(int arr[], int size){ int sum = 0; #pragma omp parallel for reduction(+:sum) for(int i=0; i<size; ++i) sum += arr; return sum; } Quelle 2 (Abschnitt: Verwendung von Reduktionen): OpenMP und inkrementelle Parallelisierung - (article in german) - Intel® Software Network Code: float DotProduct (float *a, float *b, int N) { float dot = 0.0; #pragma omp parallel for reduction(+:sum) { for (int i = 0; i < N; i++) { dot += a[i] * b[i]; } } return dot; } Ähnliche Beispiele finde ich auch auf zahlreichen anderen Seiten, Tutorials, Videos, etc. Ich habe dann mal etwas weiter probiert und mit dem was herausgekommen ist, versteh ich nun gar nichts mehr: Hier mein neuer Code (Test2.cpp): #ifdef _OPENMP #include <omp.h> #endif #include <stdlib.h> #include <stdio.h> #include <iostream> using namespace std; int main(int argc, char *argv[]) { unsigned long long test = 18446744073709551615; const unsigned long long NumValues = 24000; unsigned long long NumberOfIterations = 0; //Serielle Variante for(unsigned long long i=1;i<=NumValues;i++) { NumberOfIterations++; } printf("Benötigte Iterationen - SERIELL: %llu\n",NumberOfIterations); NumberOfIterations = 0; int NumThreads = 0; #pragma omp parallel { #pragma omp master { NumThreads = omp_get_num_threads(); printf("Anzahl Threads: %i\n",NumThreads); } } int *Threads = new int[NumThreads]; //Parallele Variante #pragma omp parallel reduction(+: NumberOfIterations) shared(Threads) { #pragma omp for schedule(static) for(unsigned long long k=1;k<=NumValues;k++) { NumberOfIterations++; Threads[omp_get_thread_num()]++; } } for(int j=0;j<NumThreads;j++) { if(j<10) { printf("Thread %i benötigte %llu Iterationen\n",j,Threads[j]); } else { printf("Thread %i benötigte %llu Iterationen\n",j,Threads[j]); } } printf("Benötigte Iterationen - PARALLEL: %llu\n",NumberOfIterations); NumberOfIterations = 0; printf("Maximalgrenzwert von unsigned long long: %llu\n",test); delete []Threads; getchar(); return 0; } Kompiliert mit: g++ -std=c++0x -m64 -fopenmp -Wall -Wextra -pedantic -pedantic-errors -O3 -s Test2.cpp -o Test2 Und nun der Output: Benötigte Iterationen - SERIELL: 24000 Anzahl Threads: 24 Thread 0 benötigte 1000 Iterationen Thread 1 benötigte 1000 Iterationen Thread 2 benötigte 1000 Iterationen Thread 3 benötigte 1000 Iterationen Thread 4 benötigte 1000 Iterationen Thread 5 benötigte 1000 Iterationen Thread 6 benötigte 1000 Iterationen Thread 7 benötigte 1000 Iterationen Thread 8 benötigte 1000 Iterationen Thread 9 benötigte 1000 Iterationen Thread 10 benötigte 1000 Iterationen Thread 11 benötigte 1000 Iterationen Thread 12 benötigte 1000 Iterationen Thread 13 benötigte 1000 Iterationen Thread 14 benötigte 1000 Iterationen Thread 15 benötigte 1000 Iterationen Thread 16 benötigte 1000 Iterationen Thread 17 benötigte 1000 Iterationen Thread 18 benötigte 1000 Iterationen Thread 19 benötigte 1000 Iterationen Thread 20 benötigte 1000 Iterationen Thread 21 benötigte 1000 Iterationen Thread 22 benötigte 1000 Iterationen Thread 23 benötigte 1000 Iterationen Benötigte Iterationen - PARALLEL: 24000 Maximalgrenzwert von unsigned long long: 18446744073709551615 Demnach hat jeder Thread wie ursprünglich angenommen, auch nur (1/AnzThreads)-tel (bei mir also 1/24 = bei 24000 Iterationen total, nur 1000 Iterationen für jeden Thread) aller Iterationen übernommen und nicht jeder Thread parallel 24000. Da das Gesamtergebnis dennoch 24000 ist, schlussfolgere ich daraus, dass meine "reduction(+: NumberOfIterations)"-Anweisung am Ende kein std::max(,) anwendet, sondern jedes Teilergebnis (1000) zu einem Ganzen (24000) summiert. Der Ablauf war also sehr wohl parallel. Was stimmt nun also und was nicht? Der eine sagt das, die anderen jenes und mein neues Beispiel-Prog "Test2" meine ursprüngliche Vermutung. Grüße Schlitzauge :):)
  15. Na dann erscheints auch logisch. Nur steht das nirgends geschrieben. D.h. mir ist bisher noch keine Dokumentation oder ein Tutorial bekannt, wo das erwähnt wird (Bücher mal außen vor, da mir gerade keine zur Verfügung stehen). Inwieweit bringt dann dieses Beispiel etwas?: int main(){ int n; printf("Geben sie eine Ganzzahl ein: "); scanf("%d", &n); // Der Initialwert von is_prime ist wichtig, da dieser auch // in die Berechnung einbezogen wird. bool is_prime = true; #pragma omp parallel reduction(&&: is_prime) { // jeder bekommt sein eigenes is_prime, // welches mit true, dem neutralen Element von &&, // initialisiert wurde. #pragma omp for for(int i=2; i<n; ++i) if(n%i == 0) is_prime = false; // Alle is_prime (auch das aus der main Funktion) werden // mittels && verknüpft. Im Klartext bedeutet dies, dass, // falls eines false ist, das Resultat false ist. } if(is_prime) printf("%d ist prim\n", n); else printf("%d ist nicht prim\n", n); } Quelle (Abschnitt "Reduction"): OpenMP Ich meine, wozu da diese OpenMP-for-Schleife, wenn doch jeder Thread das Gleiche macht? Oder hängt das damit zusammen, dass ein Unterschiedliches Verhalten (Parallelität) bei n Threads durch Kontrollstrukturen in der Schleife hervorgerufen wird (wie hier mit der IF-Abfrage)? Du hast mir ja bereits irgendwie gesagt, wie ich richtig inkrementieren muss. Aber nur mal so zum Verständnis: Ich muss nicht die Schleife an sich parallelisieren, sondern den ganzen Algorithmus der iteriert werden soll (wie in meinem Beispiel, ein simples NumberOfIterations++)? Wie genau müsste das dann ausschauen, wenn ich meine Schleife zum einfachen Hochzählen, parallelisieren möchte und das jeder Thread sich auch nur um einen Bereich von Iterationen/AnzahlThreads kümmert? Und wie veranlasst man, dass die Teilergebnisse dann nicht einfach auf ein Maximales reduziert werden, sondern auch wirklich zusammengerechnet werden? Davon ging ich bisher ja bereits aus, was die reduction()-Anweisung betrifft, was aber falsch ist, wie es sich herausstellte. Ich glaube Dir ja, dass dies schon die richtige Abbruchbedingung ist. Ich kann nur nichts mit den drei bzw. nur einer Variablen anfangen. Die Doku zu OpenMP 3.0 hab ich mir nochmal angeschaut. Aber ein "isLastThread" kann ich da nicht finden, auch sonst nicht, wenn ich Google damit füttere und auch der Kompiler kennt diese Variablen trotz omp.h nicht. Meinst Du mit "isLastThread" etwa die Funktion: omp_get_thread_num(); ? AnzahlThreads wäre demnach die Funktion: omp_get_num_threads(); ? Aber wie gesagt, weiß ich jetzt nicht, ob Du einfach nur zwei Tippfehler hattest und "Anzahl-Thread" sowie "AnzahlThreads" bei Dir nun das Gleiche sind oder nicht? Kann ich nicht nachvollziehen. Ich meine, ja, die Warnungen habe ich auch, aber mein oben stehender Code, erzeugt bei mir nur diesen Output, ohne ERRORS: NestedLoop3.cpp:13:29: warning: integer constant is so large that it is unsigned test.cpp:13: warning: this decimal constant is unsigned only in ISO C90 test.cpp:15:40: warning: integer constant is so large that it is unsigned test.cpp:15: warning: this decimal constant is unsigned only in ISO C90 test.cpp: In function ‘int main(int, char**)’: test.cpp:22: warning: ISO C++ does not support the ‘ll’ gnu_printf length modifier test.cpp:33: warning: ISO C++ does not support the ‘ll’ gnu_printf length modifier test.cpp:36: warning: ISO C++ does not support the ‘ll’ gnu_printf length modifier test.cpp: At global scope: test.cpp:11: warning: unused parameter ‘argc’ test.cpp:11: warning: unused parameter ‘argv’ Zu den Warnungen wollte ich später mal noch kommen. Alles zu seiner Zeit. Warum sollte das bei meinem Programm ein Problem darstellen, wenn doch jeder Thread - wie wir jetzt feststellten - mit eigenem Exemplar vom Datentyp "unsigned long long" das Gleiche iteriert? Im Beispiel-Code lasse ich lediglich gegen die Grenze von "unsigned long long" inkrementieren, nicht aber darüber hinaus. So, wie der Code jetzt ist, iterieren und inkrementieren Deiner Aussage nach, alle Threads doch das Gleiche. Die Reduction()-Anweisung reduziert das anschließend auf eine Instanz, wobei alle Threads am Ende in deren lokalen privaten Variable, den gleichen Wert haben drinn stehen, weshalb die Dann reduzierte Instanz natürlich den gleichen Wert erhält. Oder hab ich Dich jetzt falsch verstanden? Grüße Schlitzauge :):) PS: THX für die Literatur-Tipps, werde ich mir sicherlich auch besorgen. Mir gehts aber um das Hier und Jetzt. Literatur hilft mir also @Moment nicht weiter. Ich wollte doch einfach nur mal ein paar kleine Anfänger-Beispiele, wie das Hochzählen, wo man den Effekt der Parallelisierung beobachten kann, ausprobieren. HelloWorld brachte es nicht wirklich, da letztendlich Seriellität. :upps

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...