Seite 2 von 3

Array in Strukturen und damit auch in LinkedList´s

Verfasst: 08.04.2008 23:06
von NicknameFJ
Nochmal ein anderer Ansatz um Array´s in Strukturen und in LinkedList´s reinzupacken

Code: Alles auswählen


; --------------------------------------------------------

; Array´s im Geschwindigkeitsvergleich sowie
; Array´s in Strukturen bzw. in LinkedList´s

; --------------------------------------------------------



; --------------------------------------------------------
; Zeiten für original PB Array


DisableDebugger
    
Start = GetTickCount_()
      
          
Dim Array(999)


For lp = 1 To 100000
  
  
  For Position = 0 To 999
    Wert = Position
    Array(Position) = Wert
  Next
  
  
  
  For i = 0 To 999  
    Wert = Array(i)   
  Next
  
Next lp


Zeit = GetTickCount_()-Start
     
EnableDebugger 
    

MessageRequester("Zeit für original PB Array:   "+Str(Zeit)+" ms","")



; --------------------------------------------------------
; Zeiten für Array in Strukturen
; by NicTheQuick  -  dt. PB Forum 


Structure arr 
  StructureUnion 
    arr.l[0] 
    dummy.l 
  EndStructureUnion 
EndStructure 


DisableDebugger
    
Start = GetTickCount_()
      


Define *a.arr 
*a = AllocateMemory(SizeOf(arr) * 10) 



For lp = 1 To 100000
  
  For i = 0 To 999 
    Wert = i
    *a\arr[i] = Wert
  Next 
  
  For i = 0 To 999 
    Wert = *a\arr[i] 
  Next
  
Next

Zeit = GetTickCount_()-Start
     
EnableDebugger 
    

MessageRequester("Zeit für Array in Strukturen by NicTheQuick:   "+Str(Zeit)+" ms","")


; --------------------------------------------------------
; Zeiten für Array in Strukturen
; by Joachim Berz 



; Da die Array´s in einer Struktur stecken, kann dieses Array 
; auch in LinkedList´s verwendet werden. Der Vorteil gegenüber
; der Methode von NicTheQuick ist der, dass nach Löschen des
; LL-Element´s oder der ganzen LinkedList der durch das Array
; belegte Speicher ( =STRING ! innerhalb der Struktur) auto- 
; matisch wieder freigegeben wird, und nicht manuell mit 
; FreeMemory freigegeben werden muß. Außerdem ist diese Methode
; der Arrayzugriffe sogar schneller als die der original PB-Array´s
; und kann somit in zeitkritischen Routinen auch als Ersatz für die
; normalen Array´s dienen.

; Beachtenswert finde ich, dass hier kein optimierter Assembler-Code
; zum Einsatz kommt, sondern reiner PB-Code und dennoch ist diese
; Methode schneller als Array´s in PB - Fred was hast Du gemacht ???

; Nachteil: Der Speicherbereich des Array´s ist nicht mit Nullwerten
;           vorbelegt, kann aber noch gemacht werden


; Ist so wie es hier steht für LONG´s ausgelegt, beim Einsatz von 
; anderen Typen ist eine Anpassung erforderlich




Structure MyArray
  Array.s 
EndStructure

#TypLength = 4

DisableDebugger
    
Start = GetTickCount_()
      
Define Werte.MyArray
          
Werte\Array = Space(1000*#TypLength)
StartAddr = @Werte\Array


For lp = 1 To 100000

            
  For Position = 0 To 999
     Wert = Position
     PokeL(Position*#TypLength+StartAddr,Wert)
   Next

                
   For Position = 0 To 999
     Wert = PeekL(Position*#TypLength + StartAddr )   
   Next

Next lp


Zeit = GetTickCount_()-Start
     
EnableDebugger 
    

MessageRequester("Zeit für Array in Strukturen by Joachim Berz:   "+Str(Zeit)+" ms","sogar schneller als die original PB Array´s")



Verfasst: 09.04.2008 00:22
von Riacon
bei mir nicht:

pb: 1547
nic: 2157
joachim: 2172

Verfasst: 09.04.2008 00:58
von NicTheQuick
Bei mir sind auch die PB-Array schneller:
PB: 2414 ms
NTQ: 2744 ms
JB: 2544 ms

Meine sind wahrscheinlich langsamer als Joachims, weil 'AllocateMemory()'
die API 'globalalloc_()' nutzt und zur String-Verarbeitung aber
'heapalloc_()' genutzt wird, was ja sowieso schneller ist.

Bei Strings hab ich allerdings Angst, dass auf einmal mein Array weg ist,
weil evtl. irgendwo der Garbage Collector ein paar Nullbytes ausmacht und
alles dahinter löscht. Außerdem muss man daran denken, dass man in den
Compiler-Optionen auch den Unicod-Modus auswählen kann. Dann muss
man 'Space(1000*#TypLength)' durch 'Space(1000*#TypLength/SizeOf(Character))'
ersetzen, sonst hat man doppelt so viel Speicher allokiert, wie man
braucht.
Und falls man mit Threads arbeitet, wäre es wohl auch nötig, die
Thread-Sicherheit in den Compiler-Optionen zu aktivieren, weil man sonst
nicht weiß, ob irgendwann doch mal ein Fehler passiert.

Da fällt mir gerade auf, dass du in deinen Tests vergessen hast, bei mir
genügend Speicher zu allokieren: '*a = AllocateMemory(SizeOf(arr) * 10)'
Du allokierst nur Speicher für 10 Element, dabei nutzt 1000.

Ich werde aber weiterhin bei meiner Methode bleiben. Dann muss ich nicht
umständlich Peeken und Poken. Vor allem funktioniert das nicht mehr so
wirklich, wenn es mehr als nur ein Long ist.

Verfasst: 09.04.2008 12:07
von NicknameFJ
Zu Hause auf meinem Laptop sahen die Zeiten ungefähr so aus:

PB 1600 ms
NTQ 1700 ms
JB 1200 ms

Dies entsprach einer Zeitersparnis von 400 ms bezogen auf 1600 ms = 25%. Ich habe das Prg. jetzt mal auf Arbeit auf verschiedenen Rechnern getestet und musste leider feststellen, dass hier PB schneller ist - verstehe wer will.

Die Diskussion um die Zeiten hat sich sowieso erledigt, da gegen den Einwand von NTQ betr. Garbage Collection wohl nichts entgegengesetzt werden kann

Grüße

Joachim

Verfasst: 26.04.2008 02:01
von STARGÅTE
Hier mal mein Beitrag zum Thema 'Programmier Tipps und Tricks':
______

Viele mühen sich immer ab, wenn sie eine Zufallszahl in einem bestimmten bereich und dann auch noch eine bestimmte dichte haben wollen, dieses Macro sollte dies vereinfachen:
[RandomArea] hat geschrieben:Macro RandomArea(StartValue, EndValue, StepValue=1)
 ( Random(Int(((EndValue)-(StartValue))/(StepValue)))*(StepValue)+(StartValue) )
EndMacro
Beispiele:
Debug RandomArea(10, 20)
  ; Ganzzahlige Zufallszahlen von 10 bist 20 (beide eingeschlossen)
  ; 15, 19, 10, 13, 20
Debug RandomArea(-1.0, 1.0, 0.1)
  ; Zufallszahlen von -1 bist 1 (beide eingeschlossen) in 0.1er Abstand
  ; (rund) 0.3, -0.7, -1.0, 0.6, 0.0
______

Auch die Modulo-Funktion (Rest beim Dividieren, in PB das %) könnte man auch mal bei nicht Ganzzahligen Werten gebrauchen:
Macro ModF(Value, Factor)
 ( Value-Int(Value/Factor)*Factor )
EndMacro
Beispiele:
Debug ModF(0.7, 0.3) ; Ergebnis (rund) 0.1 
Debug ModF(13.6, 6.1) ; Ergebnis (rund) 1.4
Natürlich sind die Werte bei Floats nicht immer ganz genau!

Bemerkung:
Den Modulo einer Fließkommazahl zu nehmen ist frei erfunden,
und mathematisch nicht eindeutig definiert.
Meine Funktion ModF() ermittelt den Differenzanteil (des Divisors),
zwischen der abgerundeten Division zweier Fließkommazahlen
und der reellen Division.
Beispiel:
Int(10.7/3.3) ergibt als ganzzahliges Ergebnis 3,
die reelle Division 10.7/3.3 ergibt die Fließkommazahl 3,242424...
Die Differenz ist also 0.242424...,
dass heißt der Divisor 3.3 passt also noch 0.242424 mal in den Dividend.
0.242424 * 3.3 ist 0.8
Der "Rest" dieser Division ist also 0.8, denn
10.7 = 3*3.3 + 0.8

Re: Programmier Tipps und Tricks

Verfasst: 09.03.2011 22:48
von STARGÅTE
Da dieser kleine Code kein eigenes Thema Wert ist, hier eine Erweiterung von PeekS für Zeilenumbrüche.

Manchmal lese ich eine Komplette Datei in den Speicher, und da ReadString() ja auch mit EndOfLine umgehen kann, habe ich auch ein PeekSN() geschrieben:

Code: Alles auswählen

CompilerIf Defined(CharacterArray, #PB_Structure) = #False
	Structure CharacterArray : c.c[0] : EndStructure
CompilerEndIf

Procedure.s PeekSN(*Buffer.CharacterArray, *BufferPointer.Integer)
	Protected String.s, Index.i, EndOfLineLength.i = 1
	While *Buffer\c[Index]
		If *Buffer\c[Index] = #CR And *Buffer\c[Index+1] = #LF ; Windows
			EndOfLineLength = 2
			Break
		ElseIf *Buffer\c[Index] = #LF Or *Buffer\c[Index] = #CR ; Unix OR Mac
			Break
		EndIf
		Index + 1
	Wend
	*BufferPointer\i = *Buffer + SizeOf(Character)*(Index+EndOfLineLength)
  ProcedureReturn PeekS(*Buffer, Index)
EndProcedure

String$ = "Zeile 1"+#CRLF$+"Zeile 2"+#LF$+"Zeile 3"

*Buffer = @String$
Debug PeekSN(*Buffer, @*Buffer)
Debug PeekSN(*Buffer, @*Buffer)
Debug PeekSN(*Buffer, @*Buffer)
Der Zweite Parameter erwartet ein Pointer zu einem Pointer, der die neue Position ausgibt.
Wie im Beispiel kann man so fortlaufen einen String aus dem Speicher lesen.

EDIT: Mac hinzugefügt ...

Re: Programmier Tipps und Tricks

Verfasst: 10.03.2011 18:38
von NicTheQuick
Theoretisch müsste noch ein

Code: Alles auswählen

      ElseIf *Buffer\c[Index] = #CR
         Break
rein für Mac.

Oder in einem:

Code: Alles auswählen

      ElseIf *Buffer\c[Index] = #LF Or *Buffer\c[Index] = #CR
         Break

Re: Programmier Tipps und Tricks

Verfasst: 22.07.2015 09:28
von mhs
Ich möchte euch zwei sehr simple IF Makros, die ich sehr gerne verwende nicht vorenthalten.

1. PHP like: "c = a > b ? true : false"

Code: Alles auswählen

Macro If_set(Result, Expression, TrueValue, FalseValue)

  If Expression
    Result = TrueValue
  Else
    Result = FalseValue
  EndIf

EndMacro

Define.i a, b, c

a = 1
b = 4

If_set(c, a < b, 1, 0) : Debug c
If_set(c, a > b, 1, 0) : Debug c
2: IF Not mit Rückgabewert

Code: Alles auswählen

Macro If_not(Result, Expression)

  Result = Expression
  
  If Not Result

EndMacro

Define.i File

If_not(File, ReadFile(#PB_Any, "gibtsnicht.txt"))
  Debug "Datei konnte nicht geöffnet werden"
EndIf

Re: Programmier Tipps und Tricks

Verfasst: 12.12.2015 18:19
von GPI
CompilerIf -Else und -Endif können sehr leicht das automatische Einrücken durcheinander bringe, bspw. hier:

Code: Alles auswählen

 CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    Procedure Proc_FreeGadget(*this.Gadget)
      CompilerElse 
    ProcedureC Proc_FreeGadget(*this.Gadget)
    CompilerEndIf 
Das Problem lässt sich lösen, in den man in den Preferences unter Editor/Indentation die Schlüsselwörter ";EndIndent" (bevor -1) und ";Indent" (Bevor 1) einfügt.
dann kann man folgendes schreiben:

Code: Alles auswählen

 CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    Procedure Proc_FreeGadget(*this.Gadget)
      CompilerElse ;EndIndent
    ProcedureC Proc_FreeGadget(*this.Gadget)
    CompilerEndIf 
und kann so wieder sauber mit strg+a und strg+i schnell den gesamten Quelltext formatieren.

Re: Programmier Tipps und Tricks

Verfasst: 13.02.2016 11:51
von STARGÅTE
Hier mal eine kleine Anpassung der Mod()-Funktion von PB.
Hin und wieder stoße ich bei Z = Mod(X, Y) auf das Problem, dass PureBasic das Vorzeichen von Z von X verwendet. Das ist nicht immer gewünscht, darum hier mal eine Alternative die das Vorzeichen von Z von Y, also dem Divisor, übernimmt:

Code: Alles auswählen

Procedure.d Modulo(Value.d, Divisor.d)
  
  Protected Modulo.d
  
  Modulo = Mod(Value, Divisor)
  If (Divisor > 0.0 And Value < 0.0 And Modulo < 0.0) Or (Divisor < 0.0 And Value > 0.0 And Modulo > 0.0)
    Modulo + Divisor
  EndIf
  
  ProcedureReturn Modulo
  
EndProcedure

Code: Alles auswählen

Debug Modulo(4.00, 1.0)
Debug Modulo(2.25, 1.0)
Debug Modulo(-2.25, 1.0)
Debug Modulo(-4.00, 1.0)

Debug Modulo(4.00, -1.0)
Debug Modulo(2.25, -1.0)
Debug Modulo(-2.25, -1.0)
Debug Modulo(-4.00, -1.0)
0.0
0.25
0.75
0.0
0.0
-0.75
-0.25
0.0