Alle geraden Fibonacci Zahlen summieren
-
SeppJ schrieb:
volkard schrieb:
nachtfeuer schrieb:
...leider nirgendwo OpenMP Beispiel
Ähm, das wäre nutzlos. Kannst ja nicht einfach parallelisieren. Wie weit ist die asm-Lösung mit dem Ping-Pong-Trick?
Hmm, man könnte einen Thread die Fibonacci-Zahlen ausrechnen lassen und dem anderen die schwere, rechenintensive Aufgabe anvertrauen, auf gerade/ungerade zu prüfen und die Summe zu berechnen. Morgen kann ich eine MPI Version damit machen, wenn das jemand sehen will. Mal gucken wir langsam das Programm durch so viel Overhead wird.
Oder in der rekursiven Variante für jeden Aufruf von f einen Thread starten.
Wegen return f(n-2)+f(n-1) bietet es sich ja geradezu an, f(n-2) und f(n-1) parallel berechnen zu lassen.
-
SeppJ schrieb:
Hmm, man könnte einen Thread die Fibonacci-Zahlen ausrechnen lassen und dem anderen die schwere, rechenintensive Aufgabe anvertrauen, auf gerade/ungerade zu prüfen und die Summe zu berechnen. Morgen kann ich eine MPI Version damit machen, wenn das jemand sehen will. Mal gucken wir langsam das Programm durch so viel Overhead wird.
:):):):):):):):) ...man könnte statt 4 Mio 2^4000000-1 rechnen oder so...die
Idee mit MPI finde ich starkvolkard schrieb:
Ähm, das wäre nutzlos. Kannst ja nicht einfach parallelisieren. Wie weit ist die asm-Lösung mit dem Ping-Pong-Trick?
Der Ping-Pong-Trick ist recht ausgereift und hat, wenn man die Registerinhalte on the fly testet - oder auch nur irgendwo in den Speicher schreibt - tatsächlich zwei "Ausgänge" (und Rückfluglandepunkte) - und so eine kleine Parallelisieroptimiergrundlage.;)
-
Hier eine MPI-parallelisierte Version. Sie läuft bei mir geschätzte 0.5 Sekunden. Man lasse sich dies eine Lehre sein, dass Amdahls Gesetz kein akademisches Theoretikergeschwätz ist.
#include <iostream> #include <mpi.h> using std::cout; using std::endl; const unsigned int max = 4e6; const int work_tag = 1; const int exit_tag = 2; inline unsigned int next_fibonacci () { static unsigned int prelast = 1; static unsigned int last = 1; unsigned int current = prelast + last; prelast = last; last = current; return current; } int main (int argc, char *argv[]) { MPI_Init (&argc, &argv); int rank_size; MPI_Comm_size (MPI_COMM_WORLD, &rank_size); if (rank_size < 2) { cout << "Dieses Programm benoetigt mindestens 2 MPI Prozesse!" << endl; } else { // Alles passt, normaler Programmablauf kann starten int rank; MPI_Comm_rank (MPI_COMM_WORLD, &rank); if (rank == 0) { // Summiert gerade Fibonacci-Zahlen unsigned int sum = 0; unsigned int fibonacci = 0; MPI_Status status; do { if (fibonacci % 2 == 0) sum += fibonacci; MPI_Recv (&fibonacci, 1, MPI_INT, 1, MPI_ANY_TAG, MPI_COMM_WORLD, &status); } while (status.MPI_TAG == work_tag); cout << "Summe aller geraden Fibonacci Zahlen kleiner als " << max << " ist " << sum << "." << endl; } else if (rank == 1) { // Generiert Fibonacci Zahlen und verschickt diese unsigned int fibonacci; while ((fibonacci = next_fibonacci ()) < max) { MPI_Send (&fibonacci, 1, MPI_INT, 0, work_tag, MPI_COMM_WORLD); } // Sende exit_tag, um die anderen Prozesse zu beenden MPI_Send (0, 0, MPI_INT, 0, exit_tag, MPI_COMM_WORLD); } } MPI_Finalize (); }
Die von volkard vorgeschlagene Version mit der Threadexplosion muss aber jemand anderes programmieren.
-
Ich dachte, ich sei hart im Nehmen. Aber so eine blöde Formatierung wie bei Dir habe ich ja noch nie gesehen. Du reißt dauernd dicht zusamnmengehörende Sachen wie Typ und Variable auseinander. Das macht das Lesen viel spannender. Aber den Effekt kannst Du noch besser auskosten, wenn da ein wenig mehr Abstand ist. Ich mach's Dir mal vor.
Außerdem muß man Funktionsname und Parameterliste optisch trennen. Auch sind die geschweiften Klammern manchmal senkrecht unter dem Blockeröffner und manchmal schräg drunter. Das kann man verbessern, indem sie auch manchmal dahinter sind. An den vielen else ändere ich mal nichts, das kann man nicht überbieten.#include <iostream> #include <mpi.h> using std::cout; using std::endl; const unsigned int max = 4e6; const int work_tag = 1; const int exit_tag = 2; inline unsigned int next_fibonacci () { static unsigned int prelast = 1; static unsigned int last = 1; unsigned int current = prelast + last; prelast = last; last = current; return current; } int main (int argc, char *argv[]) { MPI_Init (&argc, &argv); int rank_size; MPI_Comm_size (MPI_COMM_WORLD, &rank_size); if (rank_size < 2) { cout << "Dieses Programm benoetigt mindestens 2 MPI Prozesse!" << endl; } else { // Alles passt, normaler Programmablauf kann starten int rank; MPI_Comm_rank (MPI_COMM_WORLD, &rank); if (rank == 0) { // Summiert gerade Fibonacci-Zahlen unsigned int sum = 0; unsigned int fibonacci = 0; MPI_Status status; do { if (fibonacci % 2 == 0) sum += fibonacci; MPI_Recv (&fibonacci, 1, MPI_INT, 1, MPI_ANY_TAG, MPI_COMM_WORLD, &status); }while (status.MPI_TAG == work_tag); cout << "Summe aller geraden Fibonacci Zahlen kleiner als " << max << " ist " << sum << "." << endl; } else if (rank == 1) { // Generiert Fibonacci Zahlen und verschickt diese unsigned int fibonacci; while ((fibonacci = next_fibonacci ()) < max) { MPI_Send (&fibonacci, 1, MPI_INT, 0, work_tag, MPI_COMM_WORLD); } // Sende exit_tag, um die anderen Prozesse zu beenden MPI_Send (0, 0, MPI_INT, 0, exit_tag, MPI_COMM_WORLD); } } MPI_Finalize (); }
-
Das ist nicht wirklich mein Stil, ich habe den Quelltext vorher bloß durch GNU-indent gejagt. Das schreckliche was du hier siehst ist der indent Standardstil.
Der Grund, warum ich das gemacht habe ist, dass mein Editor die (automatische) Einrückung mittels einer Mischung aus Tabs und Leerzeichen macht und wenn ich das hier im Forum poste, sieht mein schön eingerückter Text hinterher noch schrecklicher aus als das was indent verbrochen hat.
-
Ahh, ich habe rausgefunden wie man emacs beibringt, immer nur Leerzeichen zu verwenden. Jetzt kann ich endlich direkt aus dem Editor hier ins Forum kopieren. So sieht mein normaler Stil aus:
#include <iostream> #include <mpi.h> using std::cout; using std::endl; const unsigned int max=4e6; const int work_tag=1; const int exit_tag=2; inline unsigned int next_fibonacci() { static unsigned int prelast=1; static unsigned int last=1; unsigned int current=prelast+last; prelast=last; last=current; return current; } int main(int argc, char *argv[]) { MPI_Init(&argc, &argv); int rank_size; MPI_Comm_size(MPI_COMM_WORLD, &rank_size); if (rank_size<2) { cout<<"Dieses Programm benoetigt mindestens 2 MPI Prozesse!"<<endl; } else { // Alles passt, normaler Programmablauf kann starten int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank == 0) { // Summiert gerade Fibonacci-Zahlen unsigned int sum=0; unsigned int fibonacci=0; MPI_Status status; do { if (fibonacci%2==0) sum+=fibonacci; MPI_Recv(&fibonacci, 1, MPI_INT, 1, MPI_ANY_TAG, MPI_COMM_WORLD, &status); } while (status.MPI_TAG==work_tag); cout<<"Summe aller geraden Fibonacci Zahlen kleiner als "<<max<<" ist "<<sum<<"."<<endl; } else if (rank==1) { // Generiert Fibonacci Zahlen und verschickt diese unsigned int fibonacci; while ((fibonacci=next_fibonacci())<max) { MPI_Send(&fibonacci, 1, MPI_INT, 0, work_tag, MPI_COMM_WORLD); } // Sende exit_tag, um die anderen Prozesse zu beenden MPI_Send(0, 0, MPI_INT, 0, exit_tag, MPI_COMM_WORLD); } } MPI_Finalize(); }
-
Du setzt die geschweiften Klammern trotzdem komisch.
-
Das ist GNU-Style, beim Emacs cc-mode ist das der Default.
-
Danke SeppJ - nur so kriegen wir die Hardware aus den Strümpfen
Zum Asm Teil: es macht zwar viel mehr Spaß, sich den Algorithmus selber auszutüfteln, aber sei's drum:
Wer sich nicht so mit Asm auskennt: bitte nicht abschrecken lassen. Der Witz dieses Programms ist nur der Ping-Pong-Algorithmus und die
Prüfung des letzten Bits in einem Register.(compiliert mit FASMW)
(editiert mit Notepad++)
(debugger:debug,debugx,dosbox,braindebug)org 100h mov eax,1 ;Ausgangsbedingungen, Aerni und Bert = 1 mov ebx,1 ; mov edi,0 ;Initialisierung des Edi=Summe-Registers Nochmal: ;Man könnte Prüfen und Summieren auch auslagern, aber wir machen gleich alles in cmp eax,250000h ;einem Rutsch, 250000h = 4000000d ja Abschluss cmp ebx,250000h ja Abschluss ;Wenn alles aufsummiert ist, geht es zur Endabrechnung add eax,ebx ;jetzt gehts los: Zahl alt plus Zahl neu bt eax,0 ;Ist das erste Bit in EAX(ganz rechts) an Stelle Nr."0" eine 1? jnc Aufsummiereinganga ;nein, wir müssen die Zahl zur Gesamtsumme hinzuzählen Re1: add ebx,eax ;der zweite Teil dieser ping-pong-fibonacci algo-funktion bt ebx,0 jnc Aufsummiereingangb jmp Nochmal ;der Hauptalgorithmus ist hier fertig, es kann von vorn losgehen Aufsummiereinganga: add edi,eax ;edi dient als Aufsummierstelle call Ausgabe ;Vista startete das ComProgramm u.a. mit dem Wert FFFF in Edi, siehe oben jmp Re1 ;unsere Rückfahrkarte zur nächsten Etappe im Programm Aufsummiereingangb: add edi,ebx call Ausgabe jmp Nochmal ;-------------------------------hier unten ist nur standardmäßiger Include-Header-kram----------------------; ;-----------------------------------------------------------------------------------------------------------; Abschluss: mov eax,0 mov ecx,0 mov edx,0 mov ebx,0 mov esi,0 mov edi,0 int 20h Ausgabe: push eax ;Vorbereitungen, Register sichern und Konvertierwerte laden push ecx push edx push esi mov esi,10 ;XYZhex durch 10 teilen, um auf Dezimalwerte zu kommen mov eax,edi ;AX wird mit der Summe der Hauptrechnung geladen mov ecx,0 ;unser Zählregister muß auf Null stehen Konvertierloop: mov edx,0 ;wichtige(!) Initialisierung für die fehlerfreie Restdivision div esi ;Das Ax-Register ist hier selbstverständlich und darum nicht genannt push dx ;Rest der Division auf zur Stapelwarteschlange, hinten anstellen inc cx ;Stapeleinträge merken für die Printschleife or eax,eax ;ist eax=0? jnz Konvertierloop ;nein, play again Printloop: mov eax,00000200h ;Ah=2,d.h. ein einzelnes Zeichen (Byte), ASCII-Code in DL, ausgeben pop dx ;Sex mit dx... add dx,30h ;mögliche Ergebnis-Werte: 31,32,33,34,35,36,37,38,39 int 21h loop Printloop ;der Befehl loop liest die Anzahl der Wiederholungen aus dem CX Register mov dl,0ah ;es folgt hier noch ein klassischer Zeilenumbruch int 21h mov dl,0dh int 21h pop esi pop edx pop ecx pop eax ret
Der Hexcode für dieses Com-Programms (nenne mich .com) sieht so aus:
(wirkt aber sehr aufgeblasen mit vielen Nullen, wegen der 32-Bit Register (mov eax,1=
66B801000000))G:\debug fibo.com -d 100 1b7 193C:0100 66 B8 01 00 00 00 66 BB-01 00 00 00 66 BF 00 00 f.....f.....f... 193C:0110 00 00 66 3D 00 00 25 00-77 2F 66 81 FB 00 00 25 ..f=..%.w/f....% 193C:0120 00 77 26 66 01 D8 66 0F-BA E0 00 73 0C 66 01 C3 .w&f..f....s.f.. 193C:0130 66 0F BA E3 00 73 0A EB-D9 66 01 C7 E8 30 00 EB f....s...f...0.. 193C:0140 EC 66 01 DF E8 28 00 EB-C9 66 B8 00 00 00 00 66 .f...(...f.....f 193C:0150 B9 00 00 00 00 66 BA 00-00 00 00 66 BB 00 00 00 .....f.....f.... 193C:0160 00 66 BE 00 00 00 00 66-BF 00 00 00 00 CD 20 66 .f.....f...... f 193C:0170 50 66 51 66 52 66 56 66-BE 0A 00 00 00 66 89 F8 PfQfRfVf.....f.. 193C:0180 66 B9 00 00 00 00 66 BA-00 00 00 00 66 F7 F6 52 f.....f.....f..R 193C:0190 41 66 09 C0 75 F0 66 B8-00 02 00 00 5A 83 C2 30 Af..u.f.....Z..0 193C:01A0 CD 21 E2 F2 B2 0A CD 21-B2 0D CD 21 66 5E 66 5A .!.....!...!f^fZ 193C:01B0 66 59 66 58 C3 00 00 00 fYfX....
-
Wenn ich richtig sehe, geht das nicht mit anderen Obergrenzen, oder?
Weil die beiden Tests auf 4000000 beide am Anfang der Schleife stehen.
Einer müßte am Anfang stehen und einer nachg Re1.
-
volkard schrieb:
Wenn ich richtig sehe, geht das nicht mit anderen Obergrenzen, oder?
Weil die beiden Tests auf 4000000 beide am Anfang der Schleife stehen.
Einer müßte am Anfang stehen und einer nachg Re1.Naja, das Programm müsste genaugenommen nach jeder (PingPong)Addition den Registerinhalt auf Wertüberschreitung überprüfen
und dann das Programm beenden. Ja, es gibt hier noch einiges an Optimierungsbedarf, für alle die Lust haben...,herzlich eingeladenUnd und wenn wir das hinter uns haben, und auch die tolle MPI-Variante von SeppJ
einstudiert und durchgekaut haben, dann können wir uns auch an eine Cuda und OpenCl Möglichkeit heranwagen...;)
-
Naja, auf Überläufe überprüft hat noch keine der Implementierungen.
Irgendwie hätte ich an sowas gedacht. Völlig ungetestet, ich habe seit Jahren keinen assembler mehr benutzt, nur mal die Idee hingeschrieben, statt ping-pong nur ping-swap.
mov eax,1 ;Ausgangsbedingungen, Aerni=1 mov ebx,1 ;und Bert = 1 mov edi,0 ;Initialisierung des Edi=Summe-Registers Nochmal: ; do{ bt ebx,1 ; if(!(b&1)) jne skipSum ; //Fortsetzung add edi,ebx ; s+=b; skipSum: ; add eax,ebx ; a+=b; xchg eax,ebx ; swap(a,b); cmp ebx,250000h ; }while(b<=4000000); jle Nochmal ; //Fortsetzung fertig: call Ausgabe ; cout<<s;
-
Hey, die Kommentierung ist super.
den Befehl bt und seine Wirkung kann man schnell mit dem Debug-Clone von
Paul Vojta überprüfen (http://math.berkeley.edu/~vojta/)(unten auf der Seite ist der debug-link) (debug kann dat nich)
Der Algorithmus erinnert ein wenig an das Euklidbeispiel von der MASM-Seite
(http://msdn.microsoft.com/de-de/library/td2x50t8(v=VS.80).aspx)
und ist ziemlich SevenofNine-like
-
Danke.
Man kann noch den mathematischen Trick einbauen, daß man weiß, daß nur jede dritte Fibonacci-Zahl gerade ist.
Und da kommt auch Dein Ping-Pong-Trick zum Tragen und harmoniert fein mit dem folgenden Ping-Swap.
Die Schleife hat wie die vorige auch nur 7 Befehle, aber macht statt einem Fibonacci-Sprung gleich drei auf einmal und hat diesen unangenehmen bedingten Sprung nicht mehr in der Mitte.mov eax,1 ;Ausgangsbedingungen, Aerni=1 mov ebx,2 ;und Bert = 2 // erste gerade Fibonaci-Zahl mov edi,0 ;Initialisierung des Edi=Summe-Registers Nochmal: ; do{ add edi,ebx ; s+=b; // aufsummieren der geraden zahlen add eax,ebx ; a+=b; // ping add ebx,eax ; b+=a; // pong add eax,ebx ; a+=b; // ping xchg eax,ebx ; swap(a,b); //swap, damit die neue runde wieder mit ping beginnen darf cmp ebx,250000h ; }while(b<=4000000); jle Nochmal ; //Fortsetzung fertig: call Ausgabe ; cout<<s;
-
der Thread hier wird immer interressanter...nachdem der arme Threaderöffner gar nicht die Möglichkeit in Betracht gezogen hatte, die Werte einfach per Taschenrechner (oder im Kopf) auszurechnen, in eine Tabelle zu schreiben und einfach auszulesen...
Sonst:(@volkard) hinter dem label fertig: call Ausgabe - muß noch ein int 20h für das Programmende folgen, sonst landet der Returner im Nichts. Da die Ausgabe hier ja eigentlich nur das Ergebnis herausgeben soll, kann man die Registersicherungen weglassen und den Ret in ein Int 20h verwandeln. Man braucht sie auch nicht mehr callen, sondern nur noch hinter das Schleifenende schreiben:
org 100h mov eax,1 ;Ausgangsbedingungen, Aerni=1 mov ebx,2 ;und Bert = 2 // erste gerade Fibonaci-Zahl mov edi,0 ;Initialisierung des Edi=Summe-Registers Nochmal: ; do{ add edi,ebx ; s+=b; // aufsummieren der geraden zahlen add eax,ebx ; a+=b; // ping add ebx,eax ; b+=a; // pong add eax,ebx ; a+=b; // ping xchg eax,ebx ; swap(a,b); //swap, damit die neue runde wieder mit ping beginnen darf cmp ebx,3d0900h ; }while(b<=4000000); jle Nochmal ; //Fortsetzung Ergebnisprinter: ; cout<<s; mov esi,10 mov eax,edi mov ecx,0 mov ebx,0 Konvertierloop: mov edx,0 div esi push edx inc ecx or eax,eax jnz Konvertierloop Printloop: mov eax,00000200h pop edx add edx,30h int 21h loop Printloop Ende: int 20h
das Programm ist jetzt sehr klein und sollte scheiße schnell sein - leider bringt diese schöne und genaue Programm auch gleich einen abstrusen Fehler hervor:
Beim ersten Ausprobieren kam ein falscher Wert heraus, eine Runde zu früh ausgestiegen. Aber wieso?
Musste mal wieder alles von Hand rechnen, blöde übermüdetheit, blöde komische
Konverter...250000h !=4000000d !
Der richtige Hexwert von 4 Mio ist nämlich ist 3d0900..*verkriech* und *schäm*naja, und hier wieder die Hexwerte, diesmal viel weniger, echt schön:
G:\>debug fiboo.com -d 193C:0100 66 B8 01 00 00 00 66 BB-02 00 00 00 66 BF 00 00 f.....f.....f... 193C:0110 00 00 66 01 DF 66 01 D8-66 01 C3 66 01 D8 66 93 ..f..f..f..f..f. 193C:0120 66 81 FB 00 09 3D 00 7E-E9 66 BE 0A 00 00 00 66 f....=.~.f.....f 193C:0130 89 F8 66 B9 00 00 00 00-66 BB 00 00 00 00 66 BA ..f.....f.....f. 193C:0140 00 00 00 00 66 F7 F6 66-52 66 41 66 09 C0 75 EE ....f..fRfAf..u. 193C:0150 66 B8 00 02 00 00 66 5A-66 83 C2 30 CD 21 E2 F0 f.....fZf..0.!.. 193C:0160 CD 20 00 00 00 00 00 00-00 00 00 00 00 00 00 00 . .............. 193C:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-
Jetzt wäre noch zu klären, ob die handgeschriebenen Assemblerprogramme schneller oder langsamer sind als das was optimierende Compiler aus den C++ Programmen machen...
-
mov eax,0 ;Ausgangsbedingungen, Aerni=0 mov ebx,2 ;und Bert = 2 // zweite gerade Fibonaci-Zahl mov edi,0 ;Initialisierung des Edi=Summe-Registers Nochmal: ; do{ add edi,ebx ; s+=b; // aufsummieren der geraden zahlen lea eax,[ebx*4+eax] ; a+=4*b;// ping-pong-ping xchg eax,ebx ; swap(a,b); //swap, damit die neue runde wieder mit ping beginnen darf cmp ebx,250000h ; }while(b<=4000000); jle Nochmal ; //Fortsetzung
-
camper schrieb:
mov eax,0 ;Ausgangsbedingungen, Aerni=0 mov ebx,2 ;und Bert = 2 // zweite gerade Fibonaci-Zahl mov edi,0 ;Initialisierung des Edi=Summe-Registers Nochmal: ; do{ add edi,ebx ; s+=b; // aufsummieren der geraden zahlen lea eax,[ebx*4+eax] ; a+=4*b;// ping-pong-ping xchg eax,ebx ; swap(a,b); //swap, damit die neue runde wieder mit ping beginnen darf cmp ebx,250000h ; }while(b<=4000000); jle Nochmal ; //Fortsetzung
Werners +=4* mit lea. Da war ich auch dran, hab aber keine Doku gefunden, welche Quellregister lea erlaubt. Im Assemblercode sieht man irgendwie besser, was hübsch ist und was nicht. Kein Wunder, daß Knuth sich die Algos gerne in Assembler anschaut.
-
SeppJ schrieb:
Jetzt wäre noch zu klären, ob die handgeschriebenen Assemblerprogramme schneller oder langsamer sind als das was optimierende Compiler aus den C++ Programmen machen...
Werners
int sum = 0; for( int prev_even = 0, fibo_even = 2; fibo_even < 4E6; std::swap( prev_even += 4*fibo_even, fibo_even ) ) sum += fibo_even;
von GCC übersetzt:
movl $2, %eax xorl %ecx, %ecx flds LC0 jmp L8 .p2align 4,,7 L16: movl %edx, %eax L8: leal (%ebx,%eax,4), %edx addl %eax, %ecx movl %eax, %ebx movl %edx, 28(%esp) fildl 28(%esp) fxch %st(1) fucomi %st(1), %st fstp %st(1) ja L16
campers
int a=0; int b=2; int s=0; do{ s+=b; a+=4*b; swap(a,b); }while(b<=4000000);
wird zu
movl $2, %eax xorl %ecx, %ecx jmp L7 .p2align 4,,7 L10: movl %edx, %eax L7: leal (%ebx,%eax,4), %edx addl %eax, %ecx movl %eax, %ebx cmpl $4000000, %edx jle L10
Warum meidet der Compiler xchg? Wenn wie hier zwei Register beteiligt sind, ist es doch schnell und hat kein LOCK eingebaut.
Werners Code hat so viel f-Zeugs gehabt, weil 4e6 ein double ist. Das war natürlich nur Obfuskationsquatsch und hat in Schnellcode nichts zu suchen. Also statt 4e6 wieder 4000000.
movl $2, %eax xorl %ecx, %ecx jmp L7 .p2align 4,,7 L13: movl %edx, %eax L7: leal (%ebx,%eax,4), %edx addl %eax, %ecx movl %eax, %ebx cmpl $3999999, %edx jle L13
Auch durchaus in Ordnung. Auch ohne xchg.
Und mein Code
int main(){ int a=1; int b=2; int s=0; do{ s+=b; a+=b; b+=a; a+=b; swap(a,b); }while(a<=4000000); cout<<s<<'\n'; }
wird zu
movl $2, %edx movl $1, %eax .p2align 4,,7 L6: leal (%edx,%eax), %ecx addl %edx, %ebx leal (%ecx,%edx), %eax cmpl $4000000, %eax leal (%eax,%ecx), %edx jle L6
WAS? Er mag anscheinend lea.
-
Hätte nicht gedacht, dass dieses Thema auf so eine Resonanz stößt.