Seite 1 von 2

Programmcode optimieren

Verfasst: 04.11.2006 21:05
von ms
Hat jemand eine Idee wie man diese Auswertung signifikant beschleunigen kann ?

Das Feld ldaten.b befindet sich bereits im RAM.
anzahl.w ist ca. 3000.
Der Code wird ca. 13.000.000 mal ausgeführt.

VBA6 ist ca.30% schneller

Code: Alles auswählen

For k = 0 To 7 : m.w(k) = 0  : Next k            ;merkerfeld für neue reihe löschen

For start = anzahl.w To 1 Step -1 
X1.w = 0

For k = 1 To 7 :CC = ldaten.b(start, k)
If CC = r1.w Or CC = r2.w Or CC = r3.w Or CC = r4.w Or CC = r5.w Or CC = r6.w : X1.w = X1.w + 1 :EndIf
Next k

If x1.w >2 : m.w(X1.w) = m.w(X1.w) + 1 : EndIf       ;Wenn mehr als 2 treffer, dann eintragen

If X1.w = 3 : start1 = start: EndIf  ;wenn 3 richtige Ziehungsnummer und Datum merken
Next start

Re: Programmcode optimieren

Verfasst: 05.11.2006 00:30
von Thorsten1867

Code: Alles auswählen

For k = 0 To 7 : m.w(k) = 0  : Next k
Eigentlich sollte das reichen, um einen Array zu löschen.

Code: Alles auswählen

Dim m.w(7)
Das dürfte kürzer sein:

Code: Alles auswählen

If x1.w >2 : m.w(X1.w) = m.w(X1.w) + 1 : EndIf

Code: Alles auswählen

If x1 > 2 : m(X1.w) + 1 : EndIf

Verfasst: 05.11.2006 00:52
von ts-soft
>> VBA6 ist ca.30% schneller
VB6 halte ich zwar für unwahrscheinlich, aber VBA ist in jedem Falle langsamer :mrgreen:

Verfasst: 05.11.2006 00:53
von Thorsten1867
Ich würde das so machen:

Code: Alles auswählen

Define.w X1, start, start1, anzahl, r1, r2, r3, r4, r5, r6

; .......

Dim m.w(7) ; Array löschen
For start = anzahl To 1 Step -1 
  X1 = 0 
  For k = 1 To 7
    Select ldaten.b(start, k)
      Case r1, r2, r3, r4, r5, r6
        X1 + 1
    EndSelect
  Next k 
  If X1 > 2 : m(X1) + 1 : EndIf
  If X1 = 3 : start1 = start : EndIf
Next start

Verfasst: 05.11.2006 01:37
von Helle
Wenn man stolzer Besitzer mindestens eines Pentium 3 oder Athlon 4 ist kann folgendes die Sache enorm beschleunigen:

Code: Alles auswählen

;es wird vorausgesetzt: die jeweilige Zahlenreihe im Speicher ist aufwärts geordnet,
;also die kleinste Zahl zuerst usw. Die Zahlen sind Byte-Werte (eben wie ldaten.b)! 
;Z1 und Z2 sind die 6 Zahlen der aktuellen Ziehung, hier 1,2,3,4,5,6. Z1 und Z2 sind
;dann wie unten zu belegen! Auf Hex achten!
 
Global Anzahl.l = 3000       ;anpassen!
Global Start.l  
Global Ende.l
Global Z1.l = $0605          ;sind die letzten zwei Zahlen r6 bis r5
Global Z2.l = $04030201      ;sind die ersten vier Zahlen r4 bis r1
Global X1.w 

Start = AllocateMemory(Anzahl*7)  ;8 besser!
Ende = Start + (Anzahl*7)

!mov esi,[v_Ende]

!mov eax,[v_Z1]
!movd mm1,eax
!psllq mm1,32
!mov eax,dword[v_Z2]
!movd mm2,eax
!por mm1,mm2            ;in mm1 stehen jetzt die 6 Zahlen r1 bis r6 (Z1 und Z2)

    ;nur für Demo! Start 0-5 mit 1,2,3,4,5,6 belegen
       !mov edi,[v_Start]
       ;!add edi,21        ;für weitere Tests, immer 7-er Abstände!
       !mov eax,1
       !mov ecx,6
       W0:
       !mov [edi-1+eax],al
       !inc eax
       !dec ecx
       !jnz l_w0

For k = 0 To 7 
;   m.w(k) = 0     ;hier auskommentiert, weil nicht vorhanden
Next k            ;merkerfeld für neue reihe löschen 

;For start = anzahl.w To 1 Step -1    ;anzahl ca.3000
For x = Ende - 7 To Start Step -7        ;8 wäre natürlich besser!
X1 = 0 

;------------------------------------  
;  For k = 1 To 7 
;    CC = ldaten.b(start, k) 
;      If CC = r1.w Or CC = r2.w Or CC = r3.w Or CC = r4.w Or CC = r5.w Or CC = r6.w 
;        X1.w = X1.w + 1 
;      EndIf 
;  Next k 
;------------------------------------

;------------------------------------
!xor edi,edi
!sub esi,7
W2:
!movq mm0,[esi+edi]
!pcmpeqb mm0,mm1
!pmovmskb eax,mm0       ;für jede Übereinstimmung ist in al ein Bit gesetzt 

!mov ecx,6
W1:
!shr al,1
!adc [v_X1],0
!dec ecx
!jnz l_w1
 
!inc edi
!cmp edi,6
!jb l_w2  
  
    ;nur für Demo!
      !pushad
       Debug X1 
      !popad
;------------------------------------
   
  If X1.w >2 
;    m.w(X1.w) = m.w(X1.w) + 1     ;hier auskommentiert, weil nicht vorhanden
  EndIf       ;Wenn mehr als 2 treffer, dann eintragen 

  If X1.w = 3 
    start1 = start
  EndIf       ;wenn 3 richtige Ziehungsnummer und Datum merken 
;Next start 
Next x
Gruss
Helle
Edit: Zusatzschleife eingefügt.

Verfasst: 05.11.2006 11:16
von uweb
Es ist zwar ziemlich trivial (um nicht plump zu sagen) aber dürfte etwas bingen :

Schleifen kosten Zeit und der Zugriff auf Konstanten ist schneller als der auf Variablen !

Wenn

Code: Alles auswählen

For k = 1 To 7 ... Next k
durch sieben mal fast identischen Code ersetzt wird ist das zwar nicht elegant aber schnell.

Verfasst: 05.11.2006 20:12
von Helle
Hier eine überarbeitete (Test-)Version:

Code: Alles auswählen

;- überprüft, ob (6) Zahlen in einem Bereich von (7) Zahlen (alles Byte-Werte) vorkommen 
;- funktioniert auch mit ungeordneten Zahlenfolgen 
;- "Helle" Klaus Helbing, 05.11.2006, PB v4.01
;- nutzt MMX und SSE

Global Anzahl.l = 1     ;hier für Test nur 1
Global Start.l  
Global Z1.l = $0405070c ;sind die ersten vier Test-Zahlen (von 4,5,7,12,43,45)
Global Z2.l = $2b2df0f0 ;sind die letzten zwei Test-Zahlen mit 2 Platzhalter aufgefüllt
Global X1.w             ; diese Platzhalter evtl. nicht nötig (?), ungleich Wert von unten (f1)!

Start = AllocateMemory(Anzahl*8)  ;8 ist fast schon zwingend! Alignment!
;- Im RAM würden alle zu untersuchenden Zahlenfolgen stehen (im 8-ter Byte-Abstand) 
!mov esi,[v_Start] 
  ;- 8 Werte ins RAM schreiben für Test  
   !mov eax,50c1116h    ;5,12,17,22,34,35,43 als Simulation vorhandener Werte im RAM 
   !mov [esi+4],eax
   !mov eax,22232bf1h   ;f1 als Platzhalter muss sein! Wert > max.möglicher Wert
   !mov [esi],eax

!mov edx,0fdh           ;irgend ein nicht möglicher Wert 
!movd mm4,edx           ;"Füllwert" ungleich Null

!mov eax,[v_Z1] 
!movd mm1,eax 
!psllq mm1,32           ;um 4 Bytes nach links verschieben  
!mov eax,dword[v_Z2] 
!movd mm2,eax 
!por mm1,mm2            ;in mm1 stehen jetzt die 6 Zahlen (Z1 und Z2) 
!movq mm3,mm1           ;mm1 sichern = Testzahlen

!movq mm0,[esi] 
!movq mm5,mm0           ;mm0 sichern = Testfeld

;-------- zuerst die Linksverschiebung
!mov edi,5              ;abhängig von Anzahl der Zahlen!
W2:
!pcmpeqb mm0,mm3 
!pmovmskb eax,mm0       ;für jede Übereinstimmung ist in al ein Bit gesetzt 

!mov ecx,8 
W1: 
!shr al,1 
!adc [v_X1],0 
!dec ecx 
!jnz l_w1 

!dec edi
!jz l_w3

!psllq mm3,8
!por mm3,mm4
!movq mm0,mm5           ;mm0 wieder herstellen
!jmp l_w2

W3:
;-------- und jetzt die Rechtsverschiebung
!mov edi,6              ;abhängig von Anzahl der Zahlen!
!movq mm0,mm5           ;mm0 wieder herstellen
!movq mm3,mm1
!psrlq mm3,8
!mov edx,0fd000000h     ;irgend ein nicht möglicher Wert 
!movd mm4,edx           ;"Füllwert" ungleich Null
!psllq mm4,32

W2R:
!pcmpeqb mm0,mm3 
!pmovmskb eax,mm0       ;für jede Übereinstimmung ist in al ein Bit gesetzt 

!mov ecx,8 
W1R: 
!shr al,1 
!adc [v_X1],0 
!dec ecx 
!jnz l_w1r 

!dec edi
!jz l_w3r

!psrlq mm3,8
!por mm3,mm4
!movq mm0,mm5           ;mm0 wieder herstellen
!jmp l_w2r

W3R:
 MessageRequester("Übereinstimmungstest","Gefundene Übereinstimmungen : " + Str(X1))   
!emms
End
Gruss
Helle

Verfasst: 05.11.2006 21:58
von ms
Danke für die vielen Antworten
Eigentlich sollte das reichen, um einen Array zu löschen.
Code:
Dim m.w(7)
stimmt - aber viel schneller ?
Code:
If x1 > 2 : m(X1.w) + 1 : EndIf
stimmt
>> VBA6 ist ca.30% schneller
VB6 halte ich zwar für unwahrscheinlich, aber VBA ist in jedem Falle langsamer Mr. Green
Das Projekt ist bereits unter VBA5 / VBA6 realisiert - die Auswerungszeiten sind definitiv ca. 25 - 30 % schneller - z. B 2200 / 2900 sec.

Helle, danke für Deinen Assembler Code. Werde in dieser Richtung noch einige Test´s anstellen

Verfasst: 05.11.2006 22:12
von ts-soft
VBA5 oder 6 sind die Versionen, die sich in Office, CorelDraw u. a. befinden.
Die kompilieren nicht Nativ.
VB6 (ohne A) kompiliert nativ. da könnte es sein, aber Meßfehler halte ich für
wahrscheinlicher :mrgreen:

Verfasst: 05.11.2006 22:31
von ms
ts-soft, da liegst Du leider falsch. VBA6 (ich benutze SP6) ist ein vollwertiger Compiler. Unter der Hilfe / Info meldet sich z. B. VBA 6.0.9782. Dieser Compiler hat nichts mit den Programmierhilfen von MS Office etc. zu tun - außer vielleicht in einigen Teilen die Syntax.

Unter Visual Basic 6 mit dem Service Pack 6 sind die Auswertezeiten definitiv um 25 - 30 % schneller. Wer es nicht glaubt sollte es testen. Ich bin aber trotzdem auf Purebasic umgestiegen aus mehreren Gründen (Multiplattform, kompakter, schneller ?, kein MS !!, etc.)