PureBoard
http://forums.purebasic.com/german/

Programmier Tipps und Tricks
http://forums.purebasic.com/german/viewtopic.php?f=8&t=4840
Seite 2 von 3

Autor:  NicknameFJ [ 08.04.2008 23:06 ]
Betreff des Beitrags:  Array in Strukturen und damit auch in LinkedList´s

Nochmal ein anderer Ansatz um Array´s in Strukturen und in LinkedList´s reinzupacken

Code:

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

; 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")



Autor:  Riacon [ 09.04.2008 00:22 ]
Betreff des Beitrags: 

bei mir nicht:

pb: 1547
nic: 2157
joachim: 2172

Autor:  NicTheQuick [ 09.04.2008 00:58 ]
Betreff des Beitrags: 

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.

Autor:  NicknameFJ [ 09.04.2008 12:07 ]
Betreff des Beitrags: 

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

Autor:  STARGÅTE [ 26.04.2008 02:01 ]
Betreff des Beitrags: 

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:
Zitat:
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:
Zitat:
Macro ModF(Value, Factor)
 ( Value-Int(Value/Factor)*Factor )
EndMacro

Beispiele:
Zitat:
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

Autor:  STARGÅTE [ 09.03.2011 22:48 ]
Betreff des Beitrags:  Re: Programmier Tipps und Tricks

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:
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 ...

Autor:  NicTheQuick [ 10.03.2011 18:38 ]
Betreff des Beitrags:  Re: Programmier Tipps und Tricks

Theoretisch müsste noch ein
Code:
      ElseIf *Buffer\c[Index] = #CR
         Break

rein für Mac.

Oder in einem:
Code:
      ElseIf *Buffer\c[Index] = #LF Or *Buffer\c[Index] = #CR
         Break

Autor:  mhs [ 22.07.2015 09:28 ]
Betreff des Beitrags:  Re: Programmier Tipps und Tricks

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:
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:
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

Autor:  GPI [ 12.12.2015 18:19 ]
Betreff des Beitrags:  Re: Programmier Tipps und Tricks

CompilerIf -Else und -Endif können sehr leicht das automatische Einrücken durcheinander bringe, bspw. hier:
Code:
 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:
 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.

Autor:  STARGÅTE [ 13.02.2016 11:51 ]
Betreff des Beitrags:  Re: Programmier Tipps und Tricks

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:
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:
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)
Zitat:
0.0
0.25
0.75
0.0
0.0
-0.75
-0.25
0.0

Seite 2 von 3 Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/