Entwickler-Ecke
Algorithmen, Optimierung und Assembler - Algorithmus auf die Prozessorkerne verteilen
freedy - Di 25.11.08 17:57
Titel: Algorithmus auf die Prozessorkerne verteilen
Hi,
es fing alles ganz harmlos an. Ich wurde gefragt, wie ich einen Algorithmus schreiben würde, der ein Array (n x n) so füllt, dass in jeder Zeile und Spalte jeder Wert nur einmal vorkommt, ohne das eine Regel dahinter gesehen werden kann. Also nicht einfach nur gegeneinander verschieben.
Daraus ist dieses kleine Programm entstanden. Es misst unter anderem die Zeit, die benötigt wird, um das Array zu füllen (wird durch die StringGrid-Operationen verfälscht) und die Anzahl der notwendigen Funktionsaufrufe.
Mich frustriert dabei, dass für eine Matrix von 32 x 32 mein PC, der hier mit kumulativ auf zwei Kernen mit 4 GHz läuft, dafür am längsten braucht. Wie schaffe ich es den Algorithmus so umzustricken, dass er auf beiden Kernen ausgeführt wird.
Wie lange braucht ihr denn für eine 32er Matrix?
Als nächsten Schritt werde ich mal eine grafische Auswertung in Abhängigkeit zur Matrixgröße einbauen. ;-)
jaenicke - Di 25.11.08 18:22
Also da du jeden Versuch in das StringGrid einträgst musst du dich nicht wundern, wenn das Programm ewig braucht, wenn du das nonvisuell berechnest bist du schon deutlich schneller.
Zweitens scheinst du soweit ich das beim ersten Überfliegen gesehen habe einfach nur durch Ausprobieren die Lösungen zu finden, dass das ewig dauert, wenn du die selben Zahlen tausendmal ausprobierst ist auch klar.
Grundsätzlich liegt bei dir das Problem nicht daran ob ein oder zwei Kerne benutzt werden sondern an deiner Umsetzung würde ich sagen. Ich werde es mir am Abend nochmal anschauen, erstmal muss ich los.
Eins noch: Es ist normal, dass ein Prozessor mit mehr Kernen für einzelne Aufgaben länger braucht als ein vergleichbarer mit einem oder zwei Kernen. Das soll auch gar nicht der Vorteil einer Mehrkern-CPU sein. Dieser Algorithmus hier lässt sich in der Form wie du ihn hast schlecht aufteilen. Mit einem besseren Algorithmus schon, der würde dann auch gleich nicht alles tausendmal ausprobieren. Grundsätzlich lässt sich die Suche durchaus auf mehrere Threads verteilen.
freedy - Di 25.11.08 18:50
jaenicke hat folgendes geschrieben : |
Also da du jeden Versuch in das StringGrid einträgst musst du dich nicht wundern, wenn das Programm ewig braucht, wenn du das nonvisuell berechnest bist du schon deutlich schneller. |
Das ist natürlich klar. Es geht auch gar nicht um die Geschwindigkeit an sich. Auf den anderen PCs lief es ja auch mit ständiger Aktualisierung. Der Vergleich untereinander stört mich. :-)
jaenicke hat folgendes geschrieben : |
Zweitens scheinst du soweit ich das beim ersten Überfliegen gesehen habe einfach nur durch Ausprobieren die Lösungen zu finden, dass das ewig dauert, wenn du die selben Zahlen tausendmal ausprobierst ist auch klar. |
Nicht ganz. Es wird schon ein bisschen vorsortiert. Zumindest fische ich mir die heraus, die nicht mehr gesetzt werden dürfen.
jaenicke hat folgendes geschrieben : |
Grundsätzlich liegt bei dir das Problem nicht daran ob ein oder zwei Kerne benutzt werden sondern an deiner Umsetzung würde ich sagen. Ich werde es mir am Abend nochmal anschauen, erstmal muss ich los. |
Die Umsetzung kann natürlich fragwürdig sein. Auf die Schnelle war es halt mal eben hingefrickelt. Hast du einen besseren Vorschlag?
jaenicke hat folgendes geschrieben : |
Eins noch: Es ist normal, dass ein Prozessor mit mehr Kernen für einzelne Aufgaben länger braucht als ein vergleichbarer mit einem oder zwei Kernen. Das soll auch gar nicht der Vorteil einer Mehrkern-CPU sein. |
Dann habe ich da grundsätzlich noch die Frage, wozu denn Mehrkernsysteme überhaupt Vorteile bringen? Nur für das verteilte Rechnen?
jaenicke hat folgendes geschrieben : |
Dieser Algorithmus hier lässt sich in der Form wie du ihn hast schlecht aufteilen. Mit einem besseren Algorithmus schon, der würde dann auch gleich nicht alles tausendmal ausprobieren. Grundsätzlich lässt sich die Suche durchaus auf mehrere Threads verteilen. |
Ich bin sehr gespannt. Reicht es eigentlich schon aus, mehrere Threads anzulegen oder muss ich die Kerne, wenn das überhaupt geht, direkt ansprechen? (Die Frage erscheint mir ja selbst beim Hinschreiben schon dumm... :roll: )
GTA-Place - Di 25.11.08 18:54
17078ms bei Core2Duo E8200 (2,66 GHz). Gewerkelt hat Kern 2 mit 80%.
freedy - Di 25.11.08 18:58
19140ms Intel Pentium 4 3,01 GHz (96 % Auslastung)
Thorsten83 - Di 25.11.08 19:22
Hey,
die Zeit die das Programm braucht ist nicht wirklich deterministisch, oder?
Hab mir dein Programm nicht angeguckt, aber ich würd spontan folgendes Vorgehen vorschlagen:
1.) Fülle die Matrix vor, also z.B.
1 2 3
2 3 1
3 1 2
2)
Führe grob geschätzt 1000 "zufällige" Vertauschungen durch.
Dabei kannst du ausnutzen, dass die von dir beschriebene Ordnung invariant gegenüber dem Vertauschen von je 2 Zeilen und bzw. 2 Spalten ist.
Grüße, Thorsten
edit: "Habe mir deinen Source nicht angeguckt" trifft es wohl besser ;)
jaenicke - Di 25.11.08 20:29
freedy hat folgendes geschrieben : |
jaenicke hat folgendes geschrieben : |
Eins noch: Es ist normal, dass ein Prozessor mit mehr Kernen für einzelne Aufgaben länger braucht als ein vergleichbarer mit einem oder zwei Kernen. Das soll auch gar nicht der Vorteil einer Mehrkern-CPU sein. |
Dann habe ich da grundsätzlich noch die Frage, wozu denn Mehrkernsysteme überhaupt Vorteile bringen? Nur für das verteilte Rechnen? |
Die bringen durchaus Vorteile, aber eben nur, wenn mehrere rechenintensive Threads parallel laufen, das können mehrere Programme sein oder auch mehrere Threads in einem Programm. Wenn man aber nur ein Programm mit einem Thread parallel nutzt, dann läuft beispielsweise das System und das Programm auf dem zweiten Kern, aber mehr nicht. Und da ein einzelner Kern langsamer ist als ein Kern einer vergleichbaren CPU mit weniger Kernen läuft das einzelne Programm dann meistens langsamer.
freedy hat folgendes geschrieben : |
Reicht es eigentlich schon aus, mehrere Threads anzulegen oder muss ich die Kerne, wenn das überhaupt geht, direkt ansprechen? (Die Frage erscheint mir ja selbst beim Hinschreiben schon dumm... :roll: ) |
Ja, Threads werden automatisch auf die Kerne verteilt, je nach Rechenzeit der einzelnen Threads. Wenn du also 3 oder mehr rechenintensive Threads hast, dann kann sich auch ein QuadCore lohnen. Ich selbst habe das nicht und habe deshalb einen DualCore und selbst da rechnet meist nur ein Thread wirklich viel.
baka0815 - Di 25.11.08 21:53
Sagt doch, dass man den Haken bei "Update" rein machen muss.
202.523ms auf einem Athon X2 4400+ (unter WINE), bei 176.276 Funktionsaufrufen.
Ohne den Haken bei "Update" ist die Matrix in 1-2 Sekunden fertig.
[edit]
Zweite Versuch : 135.716ms bei 146.975 Funktionsaufrufen.
Dritter Versuch: 289.164ms bei 320.762 Funktionsaufrufen.
freedy - Mi 26.11.08 10:20
Thorsten83 hat folgendes geschrieben : |
Hey,
die Zeit die das Programm braucht ist nicht wirklich deterministisch, oder?
Hab mir dein Programm nicht angeguckt, aber ich würd spontan folgendes Vorgehen vorschlagen:
1.) Fülle die Matrix vor, also z.B.
1 2 3
2 3 1
3 1 2
2)
Führe grob geschätzt 1000 "zufällige" Vertauschungen durch.
Dabei kannst du ausnutzen, dass die von dir beschriebene Ordnung invariant gegenüber dem Vertauschen von je 2 Zeilen und bzw. 2 Spalten ist.
Grüße, Thorsten
edit: "Habe mir deinen Source nicht angeguckt" trifft es wohl besser ;) |
Hallo Thorsten,
die Idee hatte ich anfangs auch. Dadurch passiert aber folgendes: Nahezu jede Zeile enthält die gleiche Reihenfolge der Elemente. D. h. du findest in fast jeder Zeile 2, 3. Bei einer 3x3 Matrix ist das noch überschaubar. Aber auch in den Zeilen sollen die Zahlen getauscht werden.
Hier mal ein Beispiel einer 8x8 Matrix. Ich erkenne jedenfalls (fast) kein Muster.
2 6 1 3 5 4 7 8
7 1 8 5
2 3 4 6
5
2 4 8 1 6 3 7
8
3 5 7 6 2 1 4
3
4 7 1 8 5 6 2
4 7 6 2 3 1 8 5
6 5 3 4 7 8 2 1
1 8 2 6 4 7 5 3
EDIT: Oh, ich hab übersehen... die Spalten willst du ja auch tauschen. Dann könnte das wahrscheinlich wirklich besser sein und es ließe sich sogar noch in mehrere Threads aufteilen.
Gausi - Mi 26.11.08 11:06
freedy hat folgendes geschrieben : |
Dann könnte das wahrscheinlich wirklich besser sein und es ließe sich sogar noch in mehrere Threads aufteilen. |
Teil eins dieser Aussage stimme ich zu. Mehrere Threads sind hierbei aber nur sehr schwer machbar. Du arbeitest auf einer Matrix und vertauschst Spalten und Zeilen miteinander. Wie soll man das parallel machen? Wenn du zwei Zeilen miteinander vertauschst, werden dadurch alle Spalten geändert. Vertauscht man zwei Spalten, ändern sich dadurch alle Zeilen. D.h. man darf immer nur eins nach dem anderen machen.
freedy - Mi 26.11.08 11:10
Nicht ganz. Es dürfen immer parallel Zeilen ODER Spalten getauscht werden. Nur zusammen geht es nie. Ob es schon in Anbetracht der Tatsache, dass 1000 Vertauschungen relativ schnell sein sollten, sinnvoll ist, bleibt mal dahin gestellt. ;-)
Gausi - Mi 26.11.08 11:24
Joah. Und wie stellt man sicher, dass zwei Threads, die Spalten vertauschen, nicht zufällig dieselbe Spalte an eine andere Stelle tauschen wollen? Da braucht es wieder zusätzliche Synchronisation und/oder "Sperrflags", d.h. jeder Thread markiert zwei Spalten für sich. Das würde (glaube ich) nur über Critical Sections gehen, die auch nicht unbedingt zur Erhöhung der Geschwindigkeit beitragen. Machbar ist das bestimmt.
Die Frage ist aber auch, ob dann überhaupt die CPU-Leistung das Nadelöhr ist, oder die Zugriffszeiten auf den Speicher. Ich vermute eher letzteres. ;-)
freedy - Mi 26.11.08 11:38
Da gebe ich dir Recht. Und somit taugt dieses Beispiel auch nicht, eine Anwendung zu simulieren, die beide Kerne ausnutzt. Darauf wollte ich nämlich irgendwann hinaus. Nach dem ursprünglichen Prinzip war es nämlich sehr rechenintensiv. Schade...
Thorsten83 - Mi 26.11.08 12:38
Ging es dir nur darum einen mehrprozessorfähigen Algorithmus zu schreiben?
Da würde ich sonst mal alle Divide&Conquer-Algorithmen empfehlen...
freedy - Mi 26.11.08 12:49
Die Divide&Conquer - Algorithmen sind mir klar. Mir geht es allgemein um verteilte Systeme, verteiltes Rechnen. Mehrprozessorfähige Algorithmen sind ja nur ein Teilbereich. Das oben beschriebene Problem tauscht sich zwar nicht über Nachrichten aus und nutzt einen gemeinsamen Speicher, dachte aber, es wäre gut, um einen Einstieg zu finden.
delphi10 - Mi 26.11.08 21:47
Hab's auch mal gestartet mit 32x32. Zeit: 63921 msec bei 786387 Funktionsaufrufen.
Pentium 4 3.3GHz W2KSP4
Marc. - Mi 26.11.08 21:59
32x32
1. Durchlauf: 10875ms Funktionsaufrufe: 544837
2. Durchlauf: 4125ms Funktionsaufrufe: 198811
3. Durchlauf: 1890ms Funktionsaufrufe 89563
CPU: Intel Core 2 Duo T7700 @2,4Ghz (Kern1: ca. 80%; Kern2: ca 20%)
delphi10 - Do 27.11.08 13:23
Und nochmal mit Intel Core 2 2.4Ghz
22906msec 445919 Funktionsaufrufe
18546msec 364176 Funktionsaufrufe
6718msec 130796 Funktionsaufrufe
Core1 ~ 40%
Core2 ~ 70-80%
Edit: Allerdings laufen ein Sack voll administrative Zwangsprozesse im Hintergrund. Ohne die wäre ich ca. 50% performanter :evil:
freedy - Do 27.11.08 13:56
Ich finde es bei euch ja faszinierend, dass die Anzahl der Funktionsaufrufe (sie repräsentieren im Prinzip nicht alle notwendigen Versuche, eine Zahl in ein Feld zu schreiben) abnimmt, wenn ihr das Ganze mehrmals ausführt.
Da stelle ich mir doch die Frage: Warum ist das so???
delphi10 - Do 27.11.08 14:23
baka0815 hat folgendes geschrieben : |
[edit]
Zweite Versuch : 135.716ms bei 146.975 Funktionsaufrufen.
Dritter Versuch: 289.164ms bei 320.762 Funktionsaufrufen. |
Scheint aber nicht die Regel zu sein. Hier steigt's an.
Horst_H - Do 27.11.08 14:26
Hallo,
das glaube ich ja nun garnicht.
Mein erster Versuch dauerte auf meinen Notebooki 2253 ms/44804 Versuche , der zweite 3225 ms/79035 dann 14891 ms/449245 Versuche
Schau Dir doch mal Programme für Sudoku an, das ja sehr ähnliche Belegungsregeln hat, und deren zufällige Belegung anschaust.
Da wird der Zufall nur einmal pro Zelle eingesetzt. Dazu muss man aber für jede Spalte und Zeile buchführen.
Also für jede Zeile/Spalte ein Feld der möglichen Zahlen.
Für jedes Feld (ze,sp):
Schnittmenge aus möglicheZe(ze) und möglicheSp(sp) bilden.
dabei Anzahl ermmitteln
Per Zufall eine von 1 bis Anzahl auswählen
Diese aus mögliche(ze) und mögliche(sp) entfernen und Feld(ze,sp]) damit belegen.
Da braucht man nicht wie jetzt bei n=32 nicht 2e5 Fehlversuche, sondern nur 32x32=1024 Versuche.
Gruß Horst
Horst_H - Do 27.11.08 15:08
Hallo,
apropos mehrere Prozessorkerne.
Jeder Prozessorkern kann an Zeile/Spalte arbeitem die nicht von einem anderen beackert wird.
Zwei Cpu-Kernen und einem Quadrat 32x32
CPU_0: Zeile 1..16 und Spalte 1..16
zeitgleich:
CPU_1: Zeile 17..32 und Spalte 17..32.
wenn beide zeilenweise vorgehen
Dann kann z.B CPU_0 mit Zeile 17 weitzermachen, wenn CPU_1 damit schon fertig ist.
umgekehrt CPU_1 mit Zeile 1 weitzermachen, wenn CPU_0 damit schon fertig ist.
Das heisst jede CPU erhält ihren konstanten Spaltenbereich mit Breite n/Cpu_Anzahl, aber startet um n/Cpu_Anzahl versetzt.
Wenn alle CPU's fast gleich schnell sind ist es auch Cpu_Anzahl-fach schneller.
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| Schritt 1 0000xxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 xxxxxxxx xxxxxxxx xxxxxxxx |
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| Schritt 2 0000xxxx 0000xxxx xxxxxxxx xxxxxxxx xxxx1111 xxxx1111 xxxxxxxx xxxxxxxx |
..
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Schritt 5 Cpu_0 war anderweitig beschäftigt CPU_1 kann aber bei zeile 1 (oder 2) weitermachen 00001111 0000xxxx xxxxxxxx xxxxxxxx xxxx1111 xxxx1111 xxxx1111 xxxx1111 |
Gruß Horst
Thorsten83 - Do 27.11.08 15:59
Horst_H hat folgendes geschrieben : |
Hallo,
apropos mehrere Prozessorkerne.
Jeder Prozessorkern kann an Zeile/Spalte arbeitem die nicht von einem anderen beackert wird.
Zwei Cpu-Kernen und einem Quadrat 32x32
CPU_0: Zeile 1..16 und Spalte 1..16
zeitgleich:
CPU_1: Zeile 17..32 und Spalte 17..32.
|
Reden wir hier über das vertauschen von Zeilen/Spalten oder das Befüllen mit Zahlen per Backtracking?
Bei ersterem hättest du das Problem, dass Zeile 1 die Elemente [0][0] bis [0][31] beinhaltet, also alle Spalten,
bei zweiterem müsste man die Ergebnisse immer synchronisieren...
Man könnte natürlich wenn man mehr als 2 Kerne hat einen benutzen, um "swap-threads" zu erstellen, und die anderen arbeiten die dann ab,
aber ich habe so meine Zweifel ob das wirklich sinnvoll ist...
Horst_H - Do 27.11.08 18:18
Hallo,
EDIT:
Alles falsch, vo wegen der Aufteilbarkeit auf mehrere Prozessoren
Aber eine andere Idee
Ich erzeuge eine Standardmatrix die durch simple Verschiebung, die die Kriterien erfüllt
Quelltext
1: 2: 3: 4: 5:
| 12345 51234 45123 34512 23451 |
Jetzt Miller Yates Mischen (erzeugt eine zufällige Permutation) Spalten, aber nur eine Liste was gemacht werden soll:
Tausche Spalten 5-3(Random(5)+1),4-2(Random(4)+1),3-1,1-1
Das gleiche mit den Zeilen
Tausche Zeilen 5-2,4-4,1-3,1-1
Jetzt eine Liste dieser Operationen erstellen und diese mischen.
Gruß Horst
Horst_H - Fr 28.11.08 11:47
Hallo,
wenigstens eine kleine Verbesserung des Programmes soll rausspringen:
n= 500 in 610 ms
Gruß Horst
EDIT: Programm entfernt, erzeugt zu wenig Möglichkeiten
Thorsten83 - Fr 28.11.08 12:35
Ich hab mir da mal schnell was zusammengeklatscht, ich brauch für eine 64x64-Matrix und 5000 Vertauschungen 46ms...
Ist Delphi so langsam? (Also ich hab das gerade schnell in C gemacht...)
jaenicke - Fr 28.11.08 12:36
Delphi ist da normalerweise nicht wirklich langsamer, es kommt immer auf die Umsetzung an ;-).
Horst_H - Fr 28.11.08 15:55
Hallo,
@thorsten83:
Wenn du 5000 Vertauschungen bei 64x64 hast, hast Du erheblich weniger als freedy's Version und erheblich mehr als meine Version, die maximal 2*(n-1) Tauschungen vornimmt.
Meine Stoppuhr läßt das Befüllen des Stringsgrids aussen vor.
Ich habe jetzt die Matrix privat gemacht ( habe ich jetzt nicht hochgeladen ) und fülle den Stringgrid1 bei Bedarf daraus.
n = 1000 dauert jetzt 153 ms und belegt 8 MB im Taskmanger.
n= 5000 dauert jetzt 7892 ms und belegt 101 Mb
Bleibt die Frage: mache ich genug Vertauschungen.
Die Möglichkeiten sind:
Erste Zeile: Feld(0,0) =n fallend um 1 bis Feld(0,n-1)=1
Zweite Zeile Feld(1,0) =n-1 fallend bis Feld(1,n-2)=1,Feld(1,n-1)=1
..
n.te Zeile Feld(1,0) =1 bis Feld(1,n-1)=1
Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| Beispiel für n = 5 5 4 3 2 1 4 3 2 1 1 3 2 1 1 1 2 1 1 1 1 1 1 1 1 1
120 24 6 2 1 = 5!*4!*3!*2!*1! |
Das sind ( Produkt (i=1..n) n! ) Möglichkeiten // Superfactorials: product of first n factorials hilft mir irdenwie nicht, naja kleiner als (n^2) !...
Zeilen Tauschen erzeugt eine aus n! Möglichkeiten.
Spalten Tauschen erzeugt eine aus n! Möglichkeiten.
Die Abfolge der Operationen Spalte/Zeile tauschen hat (2*n)!Möglichkeiten
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| n n! Super n!^2 (2*n)! 1 1 1 1 2 2 2 2 4 24 3 6 12 36 720 4 24 288 576 40320 5 120 34560 14400 3628800 6 720 24883200 518400 479001600 7 5040 1,25411E+11 25401600 87178291200 8 40320 5,05658E+15 1625702400 2,09228E+13 9 362880 1,83493E+21 1,31682E+11 6,40237E+15 10 3628800 6,65861E+27 1,31682E+13 2,4329E+18 11 39916800 1,32895E+35 1,59335E+15 1,124E+21 12 479001600 6,3657E+43 2,29443E+17 6,20448E+23 13 6227020800 2,75273E+51 3,87758E+19 4,03291E+26 14 87178291200 2,39978E+62 7,60005E+21 3,04888E+29 |
Ab n = 11 erreiche ich irgendwie nicht mehr alle Möglichkeiten. von den 10^35
Es gibt ja auch die Möglichkeit, zwei Zeilen zweimal zu tauschen und dazwischen zwei Spalten. Das würde mein Algorithmus nicht immer können, da bei Miller yates die Obergrenze immer kleiner wird.
Schade, muss ich wieder mit Schnittmengen der Belegung arbeiten und zwar nicht nur aus Zeile und Spalte sondern bei zeilenweisem Vorgehen Zeile und Spalte einschliesslich deren folgenden Spalten.Mühselig ernährt sich das Eichhörnchen
Gruß Horst
Horst_H - So 30.11.08 09:55
Hallo,
ich habe das jetzt auch super-factorial mäßig gemischt, um bei dem Latein Quadrat hoffentlich alle Möglichkeiten zu erzeugen.
Am Beispiel n= 5.
1. Mischen (X) komplett , Damit steht dann unten rechts fest (O)
2. Mischen nur die ersten 4 Zeilen/Spalten
3. Mischen nur die ersten 3 Zeilen/Spalten
4. Mischen nur die ersten 2 Zeilen/Spalten
Quelltext
1: 2: 3: 4: 5:
| XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX->XXXXX->XXXXX->XXOOO XXXXX XXXXX XXXOO XXOOO XXXXX XXXXO XXXOO XXOOO |
n = 500 dauert statt 610 ms nun 26?? ms (Tauschen mit sich selbst werden jetzt nicht mehr ausgeführt ..)
Anzahl der Tauschungen = Summe (i := 2 to n) 2*(i-1)= 2*Summe(i=1..n-1) i
=2 * n*(n-1)/2 = n*(n-1) ~ n^2
Bei n= 64 (Thorsten83) sind es 4032 Tauschungen bei n=500 sind es schon 250000.
Gruß Horst
P.S.:
Was mich ärgert , das man für den ersten Zustand , also unten rechts eine Zahl auswählen eigentlich nur eine! beliebige Zeile oder Spalte hintauschen müsste und nicht das komplette Feld verwirbeln.
Dann wäre der Vorgang linear:
Quelltext
1: 2: 3: 4:
| bie n Wähle eine Zeile aus n tausche mit letzter Zeile n, wieder hole für j= 1 to n-2 dann eine Zeile aus n-j aus tausche mit Zeile n-j, dann eine Spalte aus n-j aus tausche mit Spalte n-j, |
Thorsten83 - So 30.11.08 13:36
Hey,
wer oder was ist Miller yates? :)
Was die Anzahl der möglichen Anordnungen angeht bin ich auf das gleiche Ergebnis gekommen, allerdings spuckt mein (zugegebenermaßen schnell zusammengeklatschter) Backtracker noch was anderes aus...
Jetzt bleibt halt die Frage: wie viele Vertauschungen brauche ich denn, damit das Ergebnis "zufällig" ist? Bzw.: wie definiert man in dem Kontext zufällig?
Die größere Anzahl von Möglichkeiten beim Vertauschen ergibt sich doch daraus, dass das Vertauschen einer Spalte und einer Zeile kommutativ ist, oder?
Horst_H - So 30.11.08 14:44
Hallo,
O.K geht der miller eben phishen...
Zitat: |
Die größere Anzahl von Möglichkeiten beim Vertauschen ergibt sich doch daraus, dass das Vertauschen einer Spalte und einer Zeile kommutativ ist, oder?
|
Ist es leider nicht.
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| Ausgang 0 1 2 3 4 1 2 3 4 0 2 3 4 0 1 3 4 0 1 2 4 0 1 2 3
Tausch Spalte 2 mit 4 Tausch Zeile 1 mit 2 Tausch Spalte 1 mit 2 Tausch Zeile 0 mit 3
3 2 1 0 4 2 1 0 4 3 4 3 2 1 0 1 0 4 3 2 0 4 3 2 1
Jetzt die selben Tauschvoränge in anderer Reihen folge
Tausch Spalte 1 mit 2 (vorher Pos 3) Tausch Zeile 0 mit 3 (vorher Pos 4) Tausch Spalte 2 mit 4 (vorher Pos 1) Tausch Zeile 1 mit 2 (vorher Pos 2)
3 2 1 0 4 0 4 3 2 1 2 1 0 4 3 1 0 4 3 2 4 3 2 1 0 |
Gruß Horst
Thorsten83 - So 30.11.08 14:54
Hey,
da hast du auch die Reihenfolge der Vertauschungen zweier Spalten verändert...
Und genau das ist wiederum nicht kommutativ wenn du eine Überschneidung bei den vertauschten Spalten hast.
Horst_H - So 30.11.08 15:20
Hallo,
deshalb fand ich es auch eine gute Idee, die Reihenfolge zu mischen, um zu mehr Varianten zu kommen.
Wie läuft den Dein Backtracking ab, Du wirst doch sicher nur aus den noch möglichen wählen. daher wundert mich etwas das Du 5000 Versuche von 4032 Möglichkeiten brauchst.
Gehtst Du strikt zeilen oder spaltenweise vor.
Ich würde anhand der Wahrscheinlichkeiten , also im ZickZack an der Nebendiagonale lang die Felder belegen.
Im Beispiel oben erst die 5 dann die 4er dann die 3 er...
Man hat bei mehr als der Hälfte überhaupt keine Möglichkeit der Auswahl
Quelltext
1: 2: 3: 4: 5: 6:
| Beispiel für n = 5 5 4 3 2 1 4 3 2 1 1 3 2 1 1 1 2 1 1 1 1 1 1 1 1 1 |
Hier könnte man vielleicht zwei Prozessoren benutzen:
Einer beginnt zeilenweise ab Zeile1 Spalte 1, der andere sobald Feld(1,1) belegt ist ab Zeile 2 die Spalte 1 runter.
Gruß Horst
P.S
Backtracking , sinnvolles Belegen ist sicher wesentlich schnellere Variante.
Statt genauso oft komplette Spalen/Zeilen zu tauschen.
Thorsten83 - So 30.11.08 15:47
Hey,
das Backtracking sieht so aus:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75:
| void delField(BOOL * feld, int n) { int i; for (i=0 ; i<n ; i++) feld[i] = FALSE; }
BOOL check(int * matrix, int index, int n, BOOL* tmp) { int i, j; int itmp; // checke die spalte: j = index%n; delField(tmp, n); for (i=0 ; i<n ; i++) { itmp = matrix[j]; if (itmp!=EMPTY) { if (tmp[itmp]==TRUE) { return FALSE; } tmp[itmp] = TRUE; j+=n; } else break; } i = index-index%n; delField(tmp, n); for (j=0 ; j<n ; j++) { itmp = matrix[i]; if (itmp!=EMPTY) { if (tmp[itmp]==TRUE) { return FALSE; } tmp[itmp] = TRUE; i++; } else break; } return TRUE; }
void genSolutions(int * matrix, int index, int n, int * result, BOOL * tmp) { int i; if (index==n*n) { (*result)++; } else { for (i=0 ; i<n ; i++) { matrix[index] = i; if (check(matrix, index, n, tmp)==TRUE) { genSolutions(matrix, index+1, n, result, tmp); } } matrix[index] = EMPTY; } } int getCount(int * matrix, int n) { int result = 0; BOOL * tmp = (BOOL*)malloc(n*sizeof(int)); genSolutions(matrix, 0, n, &result, tmp); free(tmp); return result; } |
Hoffe ihr könnt mir C was anfangen? Lazarus spinnt noch rum und ich hab ehrlich gesagt wenig Lust mich darum zu kümmern...
Die 5000 Vertauschungen waren Pi*Daumen gewählt, für kleine Matrizen wohl viel zu viel, für große wiederum nicht ausreichend...
Aber letztendlich ist doch der Fisher-Yates shuffle die Lösung, oder?
Die erste Zeile wird normal danach erstellt, bei den folgenden muss man dann halt alle Zahlen, die in der Spalte schon vorkommen, aus dem Feld streichen, wenn man das effizient macht sollte man für eine NxN-Matrix bei O(n²*log(n)) landen, oder?
edit: es soll natürlich "mit C" heißen, und zum Verständnis könnte
Quelltext
1: 2: 3: 4:
| #define EMPTY (-1) #define TRUE 1 #define FALSE 0 typedef int BOOL; |
auch noch ganz nützlich sein :)
edit2: betretenes Schweigen?
Sind da so gravierende Fehler drin, oder ist die Pointerarithmetik verwirrend?
Da Fisher-Yates irgendwie spannender als die Logikvorlesung ist hab ich gerade mal ausprobiert was passiert, wenn man mit Vertauschungen arbeitet, aber die nicht irgendwie zufällig wählt, sonst per Fisher-Yates, scheint relativ schnell und dabei auch noch zufällig zu sein :)
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| 4 3 7 9 5 1 0 6 2 8 5 4 8 0 6 2 1 7 3 9 9 8 2 4 0 6 5 1 7 3 1 0 4 6 2 8 7 3 9 5 7 6 0 2 8 4 3 9 5 1 3 2 6 8 4 0 9 5 1 7 2 1 5 7 3 9 8 4 0 6 8 7 1 3 9 5 4 0 6 2 6 5 9 1 7 3 2 8 4 0 0 9 3 5 1 7 6 2 8 4 |
Der noch nicht optimierte Code braucht für eine 2048x2048-Matrix ca. 600ms...
Horst_H - Mo 01.12.08 13:09
Hallo,
Dein Backtracking hat ja ersteinmal nur die Anzahl aller Lösungen gezählt, aber keine zufällige erzeugt.
Du wolltest doch nicht alle Varianten erzeugen und dann diesen eine zufällig auswählen.
Was ist an deiner Misch-Variante anders, wie oft tauschst Du Zeilen und Spalten.
Gruß Horst
P.S.
n=2048 1012 ms 1012 ms bei 2* (n-1) Tauschungen //wie gesagt erzeugt nicht alle Möglichkeiten (1700 Mhz PentiumM)
n=2048 ~16x3600 ms rund eine Minute (extrapoliert aus n = 512) bei 2* (n-1)^2 Tauschungen
Thorsten83 - Mo 01.12.08 13:49
Horst_H hat folgendes geschrieben : |
Hallo,
Dein Backtracking hat ja ersteinmal nur die Anzahl aller Lösungen gezählt, aber keine zufällige erzeugt.
|
Jo, das war auch die Absicht :)
Die noch offene Frage ist ja, ob man jede gültige Anordnung durch das Tauschen von Zeilen und Spalten erzeugen kann (ich denke schon), und ob bei dieser Art der Erstellung alle möglichen Ergebnisse gleich wahrscheinlich sind (ich befürchte nicht... :()
Ich führe jetzt max n Spalten- und n Zeilenvertauschungen durch, der Unterschied ist dass ich die zu vertauschenen Indizes nicht mehr rein willkürlich wähle, sondern dafür eine durch Fisher-Yates generierte Permutation der Menge {1, .., n} nehme.
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| t1 = fisher_yates_set(n); t2 = fisher_yates_set(n); t3 = fisher_yates_set(n); t4 = fisher_yates_set(n); for (i=0 ; i<n ; i++) { tauscheZeilen(matrix, t1[i], t2[i], n); tauscheSpalten(matrix, t3[i], t4[i], n); } |
Horst_H - Mo 01.12.08 14:13
Hallo,
dito, mach ich doch in der ersten Tausch Variante genauso, nur eben zusätzlich Tausch der Abfolge, welcher das Ergebnis nur selten ändert, weshalb die 2n! als Einfluß völlig daneben liegen, also berücksichtige ich das jetzt nicht mehr.
Dadurch verändert sich die Anzahl der Tauschen nicht.
Bleiben also n! x n! gegenüber SuperFac(n) ;-) , ab und zu muss man neue Bezeichner einführen.
Aber dies erzeugt ab n= 5 zuwenig Varianten.
Quelltext
1: 2: 3: 4: 5: 6: 7:
| n n! Superfac n!^2 (2*n)! 1 1 1 1 2 2 2 2 4 24 3 6 12 36 720 4 24 288 576 40320 5 120 34560 14400 3628800 <-- nur 14400 von 34560 6 720 24883200 518400 479001600 |
Gruß Horst
P.S.
Mein Versuch mit zufälliger Belegung ist momentan ähnlich lahm wie die Version des Threaderstellers. Da ich eine die Zile die nicht zu Ende gebracht werden konnte neu zufällig belege.
Da muss ich noch eine Logik einbauen, die erkennt, das wenn ich aus den möglichen Zahlen eine gewisse jetzt auswähle ich in der nächsten Spalten irgendwann auf leere Menge komme.
Thorsten83 - Mo 01.12.08 14:47
Der Witz ist halt dass mein Backtracking für eine NxN-matrix schon 161280 Lösungen findet, keine Ahnung wie es zu der Zahl kommt.
Ich denke auch dass das Befüllen per Backtracking die "zufälligste" Möglichkeit ist, das Problem ist halt dass der Algorithmus nicht zwangsläufig terminiert und auch noch relativ langsam ist...
Horst_H - Mo 01.12.08 14:53
Hallo,
bei welchem n x n ?? n = 5??
Gruß Horst
Thorsten83 - Mo 01.12.08 15:21
ups, ja :)
Horst_H - Mo 01.12.08 15:26
Hallo
das ist das 4+2/3 fache. merkwürdig.Wo habe ich den bei dem Bild den Fehler?
Quelltext
1: 2: 3: 4: 5: 6:
| Möglichkeiten der Auswahl.Beispiel für n = 5, 5 4 3 2 1 4 3 2 1 1 3 2 1 1 1 2 1 1 1 1 1 1 1 1 1 |
5!x4!x3!x2!x1! = 34560
Gruß Horst
Thorsten83 - Mo 01.12.08 15:46
Vorausgesetzt der Algorithmus haut hin...
Müsste nicht (Ai, j) = min{n-i-j, 1} sein?
Mit A € (Zn)^(nxn), wobei Zn die Restklasse modulo n sein soll...
Thorsten83 - Mo 01.12.08 15:49
Thorsten83 hat folgendes geschrieben : |
Vorausgesetzt der Algorithmus haut hin...
Müsste nicht (Ai, j) = max{n-i-j, 1} sein?
Mit A € (Zn)^(nxn), wobei Zn die Restklasse modulo n sein soll... |
edit: sry, verklickt...
muss auf jeden Fall max und nicht min sein :)
edit2: Ich schreib auch nur noch Mist... ;)
Die obige Formel gilt nur dann, wenn die Zahlen, die schon in der Spalte / Zeile stehen, alle unterschiedlich sind, was ja nicht zwangsläufig der Fall sein muss.
Horst_H - Mo 01.12.08 15:56
Hallo,
meine Werte A[i,j] sind doch MAX(n-i-j,1)
Geht dein Backtracking falsch zurück oder zählt falsch?
Nimm doch mal n = 2 oder 3 das sind doch wirkich nur 2 oder 12 Lösungen
Gruß Horst
Thorsten83 - Mo 01.12.08 16:16
Ne, nimm folgende Anfangsbelegung:
Quelltext
1: 2: 3: 4:
| 0 1 2 3 1 x x x x x x x x x x x |
Dann ist A1,1€{0, 2, 3}, es gibt also 3 und nicht wie vermutet nur noch 2 Möglichkeiten.
Horst_H - Mo 01.12.08 16:36
Hallo,
wahrlich wahr! Wenn also: in der selben Zeile in den vorangegangenen Spalten UND in der selben Spalte in den vorangegangenen Zeilen gleiche Zahlen vorkommen steigt die Anzahl der Möglichkeiten n-i-j um die Zahl der gleichen Zahlen Aber maximal auf n-max(i,j),also die längere Zeile oder Spalte an A(i,j) ist betimmend.
Erste Spalte und Zeile bleiben gleich aber dann:
Quelltext
1: 2: 3:
| 5 4 3 2 1 | 4--3+(4 gleiche /4*4(alle Kombinationen) 3,25 etc |
Das ist aber nicht mehr leicht zu berechnen
Ich bastel noch an der Logik für die Belegung herum:
wenn ich an einer Stelle eine Auswahlmenge die 4 beinhaltet habe und in den folgenden Spalten kommt jetzt überll schon 4 vor, habe ich pratisch keine Wahl sondern muss jetzt die 4 wählen.
Momentan arbeite ich mit TBits von freepascal. (XOR /AND OR ANDNOT etc)
Also bei den Spalten die Vereinigungsmenge bilden, und wenn diese Elemente aus der Auswahlmenge enthält nur diese nutzen, aber darf diese nicht nur ein-elementig ein.
Bei mehreren ist doch kein fortkommen möglich?
Gruß Horst
EDIT:
Trotz Zufallszahlen völlig symmetrisch, aber mit Fehler in Zeile 3 Spalte 3 falsch gewählt zu haben, sodass die 1 nicht mehr gesetzt werden kann.
Thorsten83 - Mo 01.12.08 19:05
Hab meinen Rechner mal gequält während ich in der Uni war,
für eine 6x6-Matrix gibt's laut Backtracking 812851200 Möglichkeiten...
Rechenzeit waren wohl ca. 17 Minuten :(
Aber nur die Zahl hilft uns ja nicht weiter.
Horst_H - Mo 01.12.08 21:14
Hallo,
Du hast deinen Rechner nicht umsonst geärgert:
http://www.research.att.com/~njas/sequences/A002860
http://en.wikipedia.org/wiki/Latin_square
Da kannst Du deinen Zahlen bestätigt finden.
Es wäre natürlich toll zu sagen:
ErzeugeLateinQuadratLfdNr(n,Random(MaxZahl(n));
ich habe mit zufälliger Auswahl auch ähnliche Ergebnisse wie freedy zu Beginn.
Natürlich ist es schneller ohne Stringgrid und ohne die Entfernung der Elemente in sortierter Form.
12 x12 in 1,8 statt 96.7 ms (100 Durchgänge), aber völlig nicht vorhersagbare Zeiten
n = 32 von 10ms bis 1107 ms
Aber mischen , selbst nxn-fach ,ist einfach viel schneller.
170 x 170 in 91 ms also die 200-fache Anzahl an Elementen gegenüber 12 x 12.
Ich glaube momentan nicht, das es viel Sinn macht, Feld für Feld zu belegen, denn die Testlogik dahinter braucht viel zuviel Zeit, sodass stumpfsinniges mischen schneller ist.
Gruß Horst
Thorsten83 - Di 02.12.08 12:57
Ansonsten hab ich da einen interessanten Ansatz gefunden, allerdings erzeugt er nur n!(n-1)! Möglichkeiten.
Zur Feier des Tages wollte ich mal eine GUI fertigmachen, und da ich kein VS hier hab in java...
Jetzt frisst folgende Zeile mir die Haare vom Kopf, die Erstellung des Feldes geht verdammt schnell(63ms für 2048x2048-Matrix):
Quelltext
1: 2: 3: 4: 5: 6:
| for (i=0 ; i<n ; i++){ for (j=0 ; j<n ; j++){ result += String.format("%3d ", matrix[i][j]); } result+="\n"; } |
Achso, fast vergessen:
Der Algorithmus füllt die erste Spalte und erste Zeile per Fisher-Yates, und füllt dann die Matrix so, dass
Ai,j = (Ai,0 + A0,j) mod n
jaenicke - Di 02.12.08 13:25
Thorsten83 hat folgendes geschrieben : |
Zur Feier des Tages wollte ich mal eine GUI fertigmachen, und da ich kein VS hier hab in java... |
Eclipse + nen GUI-Designer, fertig ;-).
Wie du den Algorithmus meinst, ist mir noch nicht so ganz klar.
Horst_H - Di 02.12.08 13:27
Hallo,
als ich so durch Internet nach latin sqaure etc suchte haben mehrere, auch Kryptografen, nur ;-) n! x (n-1)! Varianten erzeugt. ( n = 16 sind ja nur 2^84 Möglichkeiten )
Wo ist dein Problem?
Geht es Dir um die Geschwindigkeit, bei Erstellung der Ausgabe.
C#-Quelltext
1: 2: 3: 4: 5: 6:
| for (i=0 ; i<n ; i++){ for (j=0 ; j<n ; j++){ result += String.format("%3d ", matrix[i][j]); } result+="\n"; } |
Strings sinmd immer ärgerlich lahm, der wird ja auch jedesmal komplett kopiert und bei 2048 auch ~4,1 Mio mal bei zunehmender Länge also immer neuer Speicherplatz.
In Delphi könnte man result auf die richtige Länge seztzen und den Formatteil mittels copy an die richtige Stelle schreiben
Gruß Horst
freedy - Di 02.12.08 14:15
Horst_H hat folgendes geschrieben : |
Als ich so durch Internet nach latin sqaure etc suchte haben mehrere, auch Kryptografen, nur ;-) n! x (n-1)! Varianten erzeugt. ( n = 16 sind ja nur 2^84 Möglichkeiten ) |
Frage dazu: warum hat denn der Algorithmus für n x n-Matrizen dann solche Schwierigkeiten? Ich werde nun auch mal danach googlen.
Mischen ist natürlich schneller. Meine Befürchtung damals war halt nur, dass dann trotzdem noch aufeinander folgende Element zusammen stehen, z. B. 3, 4, 5 oder ähnlich. Das kann beim zufälligen Ausfüllen natürlich auch auftreten. Ist eine Frage der Häufig- und Wahrscheinlichkeit. Vielleicht müsste man Sicherstellen, dass jede Zeile bzw. Spalte ihren Platz mind. einmal wechselt.
Thorsten, kannst du deinen Java-Code mal veröffentlichen? Würde mich sehr interessieren, wie das aufgebaut ist.
Grüße
baka0815 - Di 02.12.08 14:32
Thorsten83 hat folgendes geschrieben : |
C#-Quelltext 1: 2: 3: 4: 5: 6:
| for (i=0 ; i<n ; i++) { for (j=0 ; j<n ; j++){ result += String.format("%3d ", matrix[i][j]); } result+="\n"; } | |
Anstatt die Strings aneinander zu hängen, solltest du lieber einen
StringBuffer verwenden. Da du keine Threads hast, geht auch ein
StringBuilder, der dürfte noch etwas schneller sein:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| StringBuilder sb = new StringBuilder(); for (i=0 ; i<n ; i++) { for (j=0 ; j<n ; j++){ sb.append(String.format("%3d ", matrix[i][j])); } sb.append("\n"); } result = sb.toString(); |
Horst_H - Di 02.12.08 15:49
Hallo,
@freedy:
Wenn Du Dir in screenShot _5.gif die dritte Zeile anschaust, siehst Du das spätestens in Spalte 3 die 1 hätte gesetzt werden müssen, weil in letzten beiden Spalte die 1 schon vorkommt.
Bei 1000 Zeilen und der Verarbeitung 700.ten Zeile kann es Dir ständig passieren, das irgendwelche Zahlen bis zum Ende schon komplett durch Spalten darüber belegt sind.
Frühestens ab Spalte 1000-700 = 300 könnte eine Zahl in den restlichen folgenden Spalten schon belegt sein.
Ich habe dann einfach die Belegung bei jedem neuerlichem Versagen um eine Spalte früher neu zufällig auswählen lassen, bis ich wieder in der ersten Spalte war.
Jetzt versuche ich dem vorzubeugen, indem ich eine Liste machen indem für jede Zahl die letztmögliche Spalte steht, bis zu der sie gesetzt sein muss.
(Zuerst für alle die letzte Spalte, sobald diese durch I belegt , suchen nach der neuen passenden Spalte ohne I davor)
Das wird die Sache erheblich beschleunigen, statt ständig neu anzusetzen.
Wie oben beschrieben kann es zwischen 10 und 1100 ms dauern, also ein Faktor 100 in der Zeit und das sind bestimmt nicht die größten Ausreißer.
Gruß Horst
Thorsten83 - Di 02.12.08 16:30
Hey,
ich häng das Netbeans-Projekt mal an, für alle die kein Netbeans haben hier nochmal der entscheidende Teil des Codes:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56:
| long t = System.currentTimeMillis(); Random rnd = new Random(System.currentTimeMillis()); int[] numbers = new int[n]; for (i=0 ; i<n ; i++) matrix[0][i] = i; int last = n; int tmp; int itmp; // fisher-yates: // erstelle Permutation für erste Zeile: for (i=0 ; i<n ; i++){ tmp = rnd.nextInt(last--); itmp = matrix[0][last]; matrix[0][last] = matrix[0][tmp]; matrix[0][tmp] = itmp; } System.out.println("Erste Zeile erstellt..."); // erstelle Permutation für die erste Spalte: for (i=0 ; i<n ; i++) numbers[i] = i; // wieder fisher-yates: last = n; for (i=0 ; i<n ; i++){ tmp = rnd.nextInt(last--); itmp = numbers[tmp]; numbers[tmp] = numbers[last]; numbers[last] = itmp; } System.out.println("Erste Spate erstellt..."); // jetzt noch ein swap, damit [0][0] stimmt: for (i=0 ; i<n ; i++){ if (numbers[i]==matrix[0][0]){ itmp = numbers[i]; numbers[i] = numbers[0]; numbers[0] = itmp; break; } } for (i=0 ; i<n ; i++) matrix[i][0] = numbers[i]; // fülle jetzt den rest: for (i=1 ; i<n ; i++){ for (j=1 ; j<n ; j++){ matrix[i][j] = (matrix[i][0] + matrix[0][j])%n; } } System.out.println("Rest gefuellt..."); StringBuilder bla = new StringBuilder(); System.out.println("Zeit bis hier: " + (System.currentTimeMillis() - t)); for (i=0 ; i<n ; i++){ for (j=0 ; j<n ; j++){ bla.append(String.format("%3d ", matrix[i][j])); } bla.append("\n"); System.out.println(i); } System.out.println("String erstellt..."); jLabel2.setText("Zeit war: " + (System.currentTimeMillis()-t)+ "ms"); jTextArea1.setText(bla.toString()); |
Der Stringbuilder ist auch nicht schneller, ich habe die Vermutung dass das Problem eher bei der String.Format-Methode liegt...
Horst_H - Do 04.12.08 08:25
Hallo,
die Ausgabe in ein Stringgrid dauert bei mir für n=1024 auch 5 s , Dafür belegt das Programm 120 Mb mehr Speicher.
also etwa 12 Byte pro Zelle.
Was mir noch zu deiner Belegung eingefallen ist:
Im Grunde genommen erzeugst du nur die erste Zeile und schreibst deren Verschiebungen in die folgenden Zeilen, die du wieder gemischst hast.
Das heisst, bei dieser Kontruktion ist dei Abfolge der Zahlen immer gleich.
Wenn aalso in der ersten Zeile '...1 2 5 4 ...' steht dies in (fast) allen Zeilen so.
Gruß Horst
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!