Programmier Tipps und Tricks

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
NicknameFJ
Beiträge: 324
Registriert: 03.06.2007 14:36
Wohnort: Von der Sonne aus gesehen der dritte Planet

Array in Strukturen und damit auch in LinkedList´s

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


PS: Alle im Text enthaltenen Schreibfehler sind beabsichtigt und dienen der Belustigung aller

Bild
Riacon
Beiträge: 61
Registriert: 21.01.2008 09:40

Beitrag von Riacon »

bei mir nicht:

pb: 1547
nic: 2157
joachim: 2172
pb 4.51 win7 64
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Beitrag 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.
Bild
Benutzeravatar
NicknameFJ
Beiträge: 324
Registriert: 03.06.2007 14:36
Wohnort: Von der Sonne aus gesehen der dritte Planet

Beitrag 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
PS: Alle im Text enthaltenen Schreibfehler sind beabsichtigt und dienen der Belustigung aller

Bild
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Beitrag 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
Zuletzt geändert von STARGÅTE am 02.07.2008 10:45, insgesamt 2-mal geändert.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Programmier Tipps und Tricks

Beitrag 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 ...
Zuletzt geändert von STARGÅTE am 10.03.2011 18:41, insgesamt 1-mal geändert.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Programmier Tipps und Tricks

Beitrag 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
Bild
Benutzeravatar
mhs
Beiträge: 224
Registriert: 11.01.2009 16:30
Wohnort: Graben
Kontaktdaten:

Re: Programmier Tipps und Tricks

Beitrag 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
Michael Hack

Michael Hack Software :: Softwareentwicklung | Webentwicklung | IT-Dienstleistungen
www.michaelhacksoftware.de :: www.mh-s.de :: www.michael-hack.de
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Programmier Tipps und Tricks

Beitrag 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.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Programmier Tipps und Tricks

Beitrag 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
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Antworten