Das weiß man, weil es damals als es geändert wurde ein riesiger Aufreger war. Man kann doch nicht einfach KONSTANTEN einen neuen Namen geben. Man ändert auch nicht die Windowseigenen Nachrichtennamen von WM_PAINT in W_M____PAI_NT, damit jeder der diesen Namen irgendwo in irgendeinem Programm stehen hat alles ändern muss.
Beiträge von Mars
-
-
Ich weiß leider nicht wie genau die GUISetAccelerators Funktion intern arbeitet. Es kann sein, dass es auf den ersten Blick nach Konstantem Rechenaufwand aussieht (also, dass es egal ist ob man eine oder 100 Tasten registriert). Möglicherweise ist im Hintergrund aber auch eine linear skalierende Funktion am Werk, sodass es bei einer großen Anzahl registrierter Tasten auch langsam wird.
Zudem muss man sich das Verhalten beim Tastendruck verinnerlichen. Wenn man drückt und gedrückt lässt wird sofort ein Event gesendet, dann kommt eine kurze Pause und dann kommen Events im Regelmäßigen Abstand (Gleiches Motto wie ein Textfeld in das man einen Buchstaben eintippt und die Taste gedrückt hält). _IsPressed und andere Funktionen können herausfinden ob die Taste in diesem Augenblick gedrückt ist, GUISetAccelerators kann das nicht, ob du die Taste nach 0.1 oder nach 0.2 Sek loslässt wird keinen Unterschied bei den Events machen.
lg
M -
Nur der Vollständigkeit halber eine Version mit Events und GUI:
AutoIt
Alles anzeigenOpt('GUIOnEventMode', 1) Global $hGUI, $aAccel[0][2] $hGUI = GUICreate('Test', 256, 256) GUISetOnEvent(-3, 'EVENT', $hGUI) Global $a, $b, $c $a = AddKey($aAccel, 'a') $b = AddKey($aAccel, 'b') $c = AddKey($aAccel, 'c') GUISetAccelerators($aAccel, $hGUI) GUISetState(@SW_SHOW, $hGUI) While Sleep(100) WEnd Func EVENT() Switch @GUI_CtrlId Case -3 Exit Case $a ToolTip('A Gedrückt') Case $b ToolTip('B Gedrückt') Case $c ToolTip('C Gedrückt') EndSwitch EndFunc Func AddKey(ByRef $a, $1) Local $u = UBound($a) ReDim $a[$u + 1][2] $a[$u][0] = $1 $a[$u][1] = GUICtrlCreateDummy() GUICtrlSetOnEvent($a[$u][1], 'EVENT') Return $a[$u][1] EndFunc
lg
M -
Gibts eigentlich sowas wie paddb auch für 32Bit Register ? (damit könnte man einen kompletten Pixel parallel bearbeiten und könnte sich die shifts und subs schenken).
Es wäre mir lieber, wenn man "abstrakt" folgendes: SUMABS(Pixel1 - Pixel2) anstatt die 8 Byte Brocken einzeln abzufertigen... -
Und ich hatte schon Angst vor deinem Kommentar, weil ich kein SSE benutzt habe
puh, Glück gehabt...^^ -
Ich finde es sehr schön, dass sich jemand an so eine Sache wagt (sieht mir kompliziert genug aus, dass nicht jeder User soetwas aus dem Ärmel schütteln kann) und sie auch fertigstellt.
Das Skript ist nachvollziehar aufgebaut und gut kommentiert. Das gibt Bonuspunkte
Kleine Tricks mit denen du noch arbeiten könntest: (das sind nur Denkanstöße, kein Vorwurf, dass das nicht bereits drin ist)
- Vorgerenderte Animationen
- Smoothing bzw TextRenderingHint
- (einfache) Prozedural generierte Grafik (z.B. sich bewegende geometrische Objekte)
- Mehr Puffer nutzen (z.B. frisst das Textneuzeichnen ziemlich viel Energie, ein BitBlt schlägt das um Längen)
- (einfache) Partikelengine (braucht nur 20-30 Partikel gleichzeitig anzeigen, aber damit kann man ein bisschen "Konfetti" verteilenGute Arbeit und weiter so
lg
M -
Moin,
Die folgende Funktion ermittelt den Unterschied zwischen 2 Bildern oder Bildausschnitten.
Es wird Pixelweise vorgegangen und jweils Abs(R1 - R2) + Abs(G1 - G2) + ... = Dif für jeden Pixel berechnet und aufaddiert. Anschließend wird noch durch die Anzahl Pixel geteilt um eine "Abweichung pro Pixel" herauszubekommen.Aus der Methode folgt:
- Minimalabweichung ist 0 (Beide Bilder sind absolut identisch)
- Maximalabweichung ist 255 * 3 = 765 (Jeder Pixel von Bild1 ist Schwarz, wenn er bei Bild2 weiß ist, und umgekehrt. Gilt auch für z.B. ein SWSWSW Muster bei Bild1 und ein WSWSWS Muster bei Bild2)
- Es können nur Bilder bzw Bildausschnitte gleicher Größe verglichen werden.Ich weiß nicht ob das irgendwer gebrauchen kann, aber hier ist es
Anhang enthält:
- Skript mit Funktion sowie Testskript
- 2 Bilder die ich aus Google geklaut habelg
M -
Und wir sind hier nur langweilige Skriptsprachenkiddies (wie uns die "richtigen" Programmierer gerne nennen), was würde erst passieren, wenn jemand der auch Ahnung hat den Code optimieren würde [PLENK][/ironie] ?
Jedenfalls Gute Arbeit Leute
lg
M -
Alles gute, Chef.
-
Meins wird gernicht mit verglichen, hat niemand Go, oder traut sich niemand eine fremde .exe zu starten?
(Ich bin schon eine Weile hier im Forum, ich stecke keine Viren in Exen, die ist wirklich so groß nachdem der Kompiler sie ausspuckt) -
Einen Grund kann ich dir sagen: das pow(-1, k) frisst. Selbst wenn das intern effektiv gehandelt wird hast du damit mehr Rechenaufwand als wenn du eine Vorzeichenvariable einführst.
-
Leibnitz mit TZ wie "Tür zu" [Plenk] !
-
Die ASM Version von Andy läuft bei mir in ca. 160ms. Damit ist sie knapp schneller als die Go variante.
(Hab hier einen Intel Q6600 Prozessor mit 2,4ghz, daher die miese Geschwindigkeit :D) -
Habs auch mal in Go geschrieben (natürlich auch unoptimiert, sonst macht das ja keinen Spaß :D)
C
Alles anzeigenpackage main import ( "fmt" "time" ) func main() { var runden int = 10 var pi float64 t1 := time.Now() for i := 0; i < runden; i++ { pi = Leibnitz_PI(10000000) } t2 := time.Now() fmt.Println("Benötigte Zeit [ms]: ", t2.Sub(t1).Nanoseconds()/int64(runden)/1000000) fmt.Println(" PI: ", pi) } func Leibnitz_PI(n uint32) (pi float64) { var sign float64 = -1 for n > 0 { n-- pi += sign / float64(2 * n + 1) sign = - sign } return 4 * pi }
PS: Leibnitz.
Edit1: Ich komme mit Go auf 175ms. Allerdings weiß ich nicht wie die anderen hier geposteten Programme vergleichsweise auf meinem Rechner abschneiden, hab hier ausschließlich AutoIt und Go am Start. Die .exe aus der Konsole heraus ausführen (sonst geht das Fenster direkt wieder zu und man kann das Ergebnis nicht lesen).
-
Was mir direkt auffällt ist folgendes:
(1.) Du benutzt kaum Prozessorregister, aber dafür umsomehr RAM-Speicherplätze. Versuch mal das Programm so umzubasteln, dass du möglichst wenige Ram-Zugriffe hast. Im "Notfall" (falls kein Platz mehr ist) pop und push benutzen (ist schneller als ein RAM Zugriff).
(2.) (ab hier reine Spekulation) Ich kann mich irren, aber mit dem Schleifenzähler müsste es möglich sein rückwärts zu laufen (bei 10 Mio starten), und dann aus dem "dec ecx; cmp ecx, 0; jnz loop" das cmp rauszunehmen und zu "dec ecx; ja loop" zu machen. Ggf (muss man testen) ist auch sub ecx, 1 schneller als dec ecx (je nach Prozessor).
Edit1: (2.1) (habs jetzt nachgelesen). Schleifenvariable in ecx stecken (nicht edx, das ist doch nicht schön :D). Anschließend kann man entweder wie in (2.) verfahren, oder mit dem "loop loop1" (müsstest deinen loop ggf umbenennen sonst ist man verwirrt^^) gleichzeitig "dec ecx" und "ja loop1" ausführen. (hier muss man auch mit der Stopuhr schauen was von den beiden Varianten schneller ist)
(3.) Andy wird bestimmt noch irgendwas zum SSE sagen, was hier fehltEdit2: Spalte die Leibniz Summe auf.
Du hast in jedem Schleifendurchlauf ein not [sign], und eine Sprungstelle an der du entscheidest ob du addierst oder subtrahierst. Spalte die Summe in 2 Summen auf:
(1.) Summe von 0 bis N/2 [1/(4k+1)] -> Das sind alle positiven Werte bis N
(2.) Summe von 1 bis N/2 [1/(4k-1)] -> Das sind alle negativen Werte bis N
Jetzt kannst du die beiden Werte voneinander abziehen und hast damit kein wechselndes Vorzeichen und kein unnötiges If in der Schleife. (so wie du das mit dem [store] gelöst hast (das muss ein ein Register! Da wird doch andauernd was addiert :D), kann man das hier auch machen. Nur mit [store] += 4)lg
M -
AutoIt
Alles anzeigen#include <Array.au3> Local $a = [1, 2, 3, 4, 5, 6], $b = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] Local $c = [1, ConsoleWrite, Eval, 3.141], $d[100], $e = [Default, Null] Local $f = Foo($a, $b, $c, $d, $e) _ArrayDisplay($f) Func Foo($a0, $a1 = 0, $a2 = 0, $a3 = 0, $a4 = 0) Local $aU = [UBound($a0), UBound($a1), UBound($a2), UBound($a3), UBound($a4)], $iMax = $aU[0], $n = @NumParams For $i = 1 To $n - 1 Step 1 If $iMax < $aU[$i] Then $iMax = $aU[$i] Next Local $aRet[$iMax][$n] For $i = 0 To $aU[0] - 1 Step 1 $aRet[$i][0] = $a0[$i] Next If $n > 1 Then For $i = 0 To $aU[1] - 1 Step 1 $aRet[$i][1] = $a1[$i] Next EndIf If $n > 2 Then For $i = 0 To $aU[2] - 1 Step 1 $aRet[$i][2] = $a2[$i] Next EndIf If $n > 3 Then For $i = 0 To $aU[3] - 1 Step 1 $aRet[$i][3] = $a3[$i] Next EndIf If $n > 4 Then For $i = 0 To $aU[4] - 1 Step 1 $aRet[$i][4] = $a4[$i] Next EndIf Return $aRet EndFunc
Für beliebige Arrays. (Hab die Funktion aber nicht getestet, also am besten selbst nochmal drüberschauen)
M
-
Villeicht klappt es ja indirekt. In 10 Jahren haut ein AutoIttyp auf F5. Der Interpreter ist durch den besseren Compiler 3x so schnell -> Der AutoIt-Code ist auch 3x so schnell^^ Dafür dürfen die aber keine "Bugfixes" mehr einbauen, die 300kb große LuTs oder 50KB Workaround für EINEN Bug liefern. (Oder einfach den Code mal Open Source machen und die Community mal richtig toben lassen, da hätte ich auch noch Spaß dran :D)
-
Das "Auf den nächsten Interpreter/Compiler warten und damit das Programm schneller machen" wollte ich bei AutoIt auch schonmal machen. (mein Code holt meistens schon viel aus der dem Interpreter raus, sodass am Code herumschrauben viel Arbeit und wenig Erfolg bereutet). Aber außer, dass der Interpreter immer größer und langsamer (nur in manchen Bereichen) wird ändert sich da nicht viel^^
Das einige Compiler immer suboptimalen Code erzeugen (für das jeweilige System) liegt zum Teil (nicht vollkommen) daran, dass die Abwärtskompatibilität gewahrt bleiben muss und daher weniger Energie in Sachen wie "Neue Prozessorerweiterungen" usw gesteckt wird. Ich wette aber, dass es Compiler gibt die den Prozessor bis zum Rand ausreizen können. Wenn man sich sowas wie z.B. die Playstation 3 ansieht und dann darauf achtet was für eine gigantische Entwicklung die Spiele in ihrer Lebenszeit (auf der gleichen Hardware wohlgemerkt) durchgemacht haben merkt man, dass da an allen Ecken geschraubt wurde. Und ich glaube nicht, dass da die Mehrzahl der Programmierer immer fähiger wurden, sondern, dass die Engines weiterentwickelt sind (besserer, schnellerer Code, hier braucht man ggf Leute die sich auskennen), und dass die Compiler die Kiste zum Schluss besser ausnutzen. Das hat aber auch ein Jahrzehnt gedauert bis die Kiste ihr volles Potential entfalten konnte und die Software die Hardware eingeholt hatte.
Solange jedes Jahr eine "neue Architektur" rauskommt und kein "Standard" länger als ein Jahr aktuell ist kann ich auch die Compilerhersteller verstehen wenn sie da keine Lust mehr haben. Die Computer die aktuell genutzt werden sind 0 bis 10 Jahre alt und haben 32 oder 64Bit. Jede "Generation" hat irgendwelche krassen Erweiterungen. Wenn man das optimal nutzen will müsste man den Code 50x Kompilieren (für jedes System einzeln) und beim Programmstart die richtige Version wählen (Weichen im Programm selbst sind ineffizient, da es dann bei jedem "neuen" Befehl/Funktion nen riesen Overhead gibt um zum auszuführenden Code zu springen). Das ist halt alles ne blöde Kiste. Von daher: Tee trinken und entspannen und warten bis Skynet die Welt übernimmt^^
-
Man muss immer irgendwie die goldene Mitte finden.
-
Ich programmiere Folgendermaßen (wenn es schnell sein muss):
1. Programm quick n Dirty zusammenstricken das die gewünschte Funktionalität zu 100% erfüllt.
2. Das gleiche Programm nochmal von Grund auf neu schreiben und dabei aus den Fehlern der Vorgängerversion lernen. Außerdem kann man das Problem auch im Kopf wesentlich effizienter lösen, wenn man schonmal ein Programm für diesen Zweck geschrieben hat. Plötzlich sieht man Wege die einem beim ersten Durchlauf nicht einfallen konnten, weil man entweder noch keinen vollständigen Überblick über das Problem hatte, oder noch nicht wusste wie man später mit zwischenzeitlich auftauchenden Daten/Rechnungen verfährt. Das alles lässt sich nun viel effizienter gestalten.
3. Optimierung von Kleinigkeiten (vorallem, wenn man nicht AutoIt nutzt und Datentypen wichtig sind) wie "ich muss viel zu viel Casten, aber wenn ich irgendwo ganz vorne einen anderen Datentyp benutze muss ich an 5 weiteren Stellen ebenfalls umschalten... usw usw" Da gibt es immer eine kleinst mögliche Anzahl Umwege (kleinst mögliche Anzahl Casts/Funktionsaufrufe/Variablen/Byref oder Byval/usw) die man versucht im Folgenden zu erreichen. (Man sucht also den Code der einen kleinen Problemausschnitt mit weniger Aufwand erledigt als vorher, ohne dabei den input oder output des Ausschnitts anzufassen)
4. F5
5. Wenn es wirklich schnell sein muss und man noch nicht zufrieden ist, zurück zu Schritt 3 gehen und etwas herumspielen und schauen was sich dadurch verändert. In vielen Fällen lassen sich da einige Prozente rausholen. (Vorallem muss man für Schritt 3 im Prinzip nichts besonderes können, man "bastelt" ja nur etwas am sowieso vorhandenen Code herum ohne ihn in irgendeiner Weise von der Funktionalität her zu verändern)Den fertigen Code schaue ich mir aber meistens nicht an. Dafür hab ich nicht den Nerv und in vielen Fällen auch nicht die Qualifikation.
In AutoIt ist der Weg zum Tempo relativ einfach: Man nutzt stattdessen ASM
Alle Calls via Pointer aufrufbar machen. Variablen und Arrays in Structs lagern. Schleifen mit vielen Durchgängen durch ASM ersetzen. Fertig. Das macht zwar das "Umfeld" etwas langsamer (Structs sind teils langsam, dabei müssten sie eigentlich schnell sein^^), sofern der Knackpunkt aber eine einfache Stelle ist die man locker umschreiben kann gibts keine Probleme.)Allgemein ist auch ganz praktisch: Wer Funktionen wie log, exp, pow, usw benutzt kann (falls Genauigkeit nicht wichtig ist) mit einigen wenigen Grundoperationen jedes Prozessors eine gute Approximation bekommen. Vorallem in InnerLoops haut das richtig rein, wenn man bei pow nicht 10 Schritte (angenommen die Biblipthek die man nutzt hat per default so viele), sondern nur 3 oder so benutzt.
Das war jetzt nur ganz allgemein. Der Rest wurde schon genannt, ist offensichtlich oder wird noch genannt
lg
M