Tuesday 8 August 2017

C Code Exponentiell Gleitender Durchschnitt

Ich habe dies mit dem Visual C-Profiler profiliert, und es macht etwa 35 der Laufzeit. Dieser exponentielle gleitende Durchschnitt wird mehr als eine Billion Mal genannt, weil er wiederholt bei der Verarbeitung von mehr als 400 Gigabyte Daten verwendet wird. Die Daten kommen aus einem Raid Level 0 Festplattenlaufwerk-Array, so dass das Lesen der Daten für weniger als 5 der Zeit. Die Größe des Preises ist etwa 100.Ich beschleunigte es ursprünglich um den Faktor 4, indem es so viele Daten wie möglich vorberechnet. Dann konnte ich es nochmal um einen Faktor von ndash steigern PaeneInsula Okt 30 11 um 20:41 Ich konnte die Geschwindigkeit wieder um den Faktor 12 erhöhen, indem ich sie multithreading (die Natur der Daten ist so, dass sie multithreaded in sein kann So dass die Last perfekt ausbalanciert ist.) Und ich habe es läuft auf einem i7 990x (das hat 6 Kerne, hyperthreaded von insgesamt 12), übertaktet. Ndash PaeneInsula Oct 30 11 at 20:51 Sicher, Multithreading kann helfen. Aber Sie können fast sicher die Leistung auf einem einzigen Gewinde-Maschine zu verbessern. Zuerst berechnen Sie es in die falsche Richtung. Nur die modernsten Maschinen können negative Vorwärts-Prefetching. Fast alle Maschinen sind schneller für Einheit Fortschritte. D. h. Ändern Sie die Richtung des Arrays, so dass Sie scannen von niedrig zu hoch anstatt hoch zu niedrig ist fast immer besser. Als nächstes, umschreiben ein bisschen - erlauben Sie mir, die Variablennamen zu verkürzen, um es einfacher zu machen: By the way, Ich werde mit der Verwendung von Stenogrammen p für Preis und s für Glättung, um die Eingabe zu speichern. Ich bin faul. Aber es ist wahrscheinlich schneller zu tun Die Latenz zwischen avgi und avgi-2 ist dann 1 multiplizieren und addieren, anstatt eine Subtraktion und eine Multiplikation zwischen avgi und avgi-1. D. h. Mehr als doppelt so schnell. Im Allgemeinen möchten Sie die Wiederholung so umschreiben, dass avgi in Form von avgj für j so weit zurück berechnet wird, wie Sie gehen können, ohne das Gerät auszufüllen, entweder Ausführungseinheiten oder Register. Sie sind im Grunde mehr multipliziert insgesamt, um weniger Ketten von Vielfachen (und subtrahiert) auf dem kritischen Pfad zu erhalten. Überspringen von avgi-2 bis avgi ist einfach, können Sie wahrscheinlich drei und vier. Genau wie weit, hängt davon ab, was Ihre Maschine ist, und wie viele Register Sie haben. Und die Latenz der Gleitkomma-Addierer und Multiplikator. Oder besser noch, den Geschmack der kombinierten Multiply-Add-Anweisung haben Sie - alle modernen Maschinen haben sie. Z. B. Wenn der MADD oder MSUB 7 Zyklen lang ist, können Sie bis zu 6 andere Berechnungen in seinem Schatten tun, auch wenn Sie nur eine einzige Gleitkommaeinheit haben. Vollständig pipeline. Und so weiter. Weniger, wenn alle anderen Zyklen pipelined, wie für doppelte Genauigkeit auf älteren Chips und GPUs üblich ist. Der Assembler-Code sollte softwarepipelinisiert sein, so dass sich unterschiedliche Loop-Iterationen überlappen. Ein guter Compiler sollte das für Sie tun, aber möglicherweise müssen Sie den C-Code umschreiben, um die beste Leistung zu erhalten. Übrigens: Ich meine nicht, dass du ein Array von avg erstellen solltest. Stattdessen würden Sie zwei Durchschnitte benötigen, wenn avgi in Bezug auf avgi-2 berechnet wird, und so weiter. Sie können ein Array von avgi verwenden, wenn Sie wollen, aber ich denke, dass Sie nur 2 oder 4 avgs, genannt, kreativ, avg0 und avg1 (2, 3.) haben müssen, und drehen sie. Diese Art von Trick, Aufteilung eines Akkumulators oder Durchschnitt in zwei oder mehr, kombiniert mehrere Stufen der Wiederholung, ist in Hochleistungs-Code gemeinsam. Ach ja, ss vorberechnen usw. Wenn ich es richtig gemacht habe, wäre dies in unendlicher Genauigkeit identisch. (Bitte überprüfen Sie mich, bitte.) Allerdings in endlichen Präzision FP Ihre Ergebnisse können sich unterscheiden, hoffentlich nur geringfügig, wegen der verschiedenen Rundungen. Wenn das Abrollen korrekt ist und die Antworten signifikant unterschiedlich sind, haben Sie wahrscheinlich einen numerisch instabilen Algorithmus. Du bist derjenige, der es weiß. Hinweis: Fließkomma-Rundungsfehler ändern die niedrigen Bits Ihrer Antwort. Beide, weil der Umzug des Codes, und mit MADD. Ich denke, dass ist wahrscheinlich okay, aber Sie müssen entscheiden. Hinweis: Die Berechnungen für avgi und avgi-1 sind nun unabhängig. So können Sie einen SIMD-Befehlssatz wie Intel SSE2 verwenden, der den Betrieb auf zwei 64-Bit-Werten in einem 128-Bit breiten Register zu einem Zeitpunkt ermöglicht. Das ist gut für fast 2X, auf einer Maschine, die genug ALUs hat. Wenn Sie genug Register haben, um avgi in Bezug auf avgi-4 umzuschreiben (und ich bin sicher, dass Sie auf iA64 tun), dann können Sie 4X breit gehen, wenn Sie Zugang zu einer Maschine wie 256 Bit AVX haben. Auf einem GPU. Können Sie für tiefere Wiederholungen gehen, umzuschreiben avgi in Bezug auf avgi-8, und so weiter. Einige GPUs haben Anweisungen, die AXB oder sogar AXBY als einen Befehl berechnen. Obwohl das für 32-Bit üblicher ist als für 64-Bit-Präzision. An einem gewissen Punkt würde ich wahrscheinlich beginnen zu fragen: wollen Sie dies auf mehrere Preise zu einem Zeitpunkt tun nicht nur dies hilft Ihnen mit Multithreading, wird es auch für den Betrieb auf einem GPU. Und mit breiten SIMD. Minor Late Addition Ich bin ein bisschen peinlich, nicht anzuwenden Horners Rule auf Ausdrücke wie etwas effizienter. Leicht abweichende Ergebnisse mit Rundung. In meiner Verteidigung sollte jeder anständige Compiler dies für Sie tun. Aber Hrners Regel macht die Abhängigkeit Kette tiefer in Form von Multiplikatoren. Möglicherweise müssen Sie die Schleife ein paar Mal entrollen und pipelined. Oder Sie können tun, wo Sie precalculateIs es möglich, einen gleitenden Durchschnitt in C ohne die Notwendigkeit für ein Fenster von Proben Ive gefunden, dass ich ein bisschen optimieren kann, indem Sie eine Fenstergröße, die eine Macht von zwei, um für Bit-Verschiebung statt zu ermöglichen Der Teilung, aber nicht brauchen einen Puffer wäre schön. Gibt es eine Möglichkeit, ein neues gleitendes Durchschnittsergebnis nur als Funktion des alten Ergebnisses und des neuen Beispiels auszudrücken, definieren Sie einen beispielhaften gleitenden Durchschnitt in einem Fenster von 4 Proben: Add new sample e: Ein gleitender Durchschnitt kann rekursiv implementiert werden , Aber für eine exakte Berechnung des gleitenden Durchschnitts müssen Sie sich an die älteste Eingangsabfrage in der Summe (dh die a in Ihrem Beispiel) erinnern. Für einen N-gleitenden Durchschnitt berechnen Sie: wobei yn das Ausgangssignal und xn das Eingangssignal ist. Gl. (1) können rekursiv geschrieben werden, also müssen Sie sich stets an die Stichprobe xn-N erinnern, um (2) zu berechnen. Wie von Conrad Turner angemerkt, können Sie stattdessen ein (unendlich langes) exponentielles Fenster verwenden, mit dem Sie die Ausgabe nur aus dem vergangenen Ausgang und dem aktuellen Eingang berechnen können. Dies ist jedoch kein normaler (ungewichteter) gleitender Durchschnitt, sondern ein exponentieller Wert Gewogenen gleitenden Durchschnitt, wo die Proben in der Vergangenheit ein geringeres Gewicht erhalten, aber (zumindest in der Theorie) man nie etwas vergessen (die Gewichte nur kleiner und kleiner für Proben weit in der Vergangenheit). Ich habe einen gleitenden Durchschnitt ohne einzelnen Element-Speicher für ein GPS-Tracking-Programm, das ich geschrieben habe. Ich beginne mit 1 Probe und dividiere durch 1, um die aktuelle Durchschn. Ich füge dann anothe Probe und dividiere durch 2 zu den aktuellen Durchschn. Das geht so lange weiter, bis ich auf die Länge des Durchschnitts komme. Jedes Mal danach, füge ich in der neuen Probe, erhalten Sie den Durchschnitt und entfernen Sie diesen Durchschnitt aus der Gesamtmenge. Ich bin kein Mathematiker, aber das schien ein guter Weg, es zu tun. Ich dachte, es würde den Magen eines echten Mathematik-Kerl, aber es stellt sich heraus, es ist eine der akzeptierten Möglichkeiten, es zu tun. Und es funktioniert gut. Denken Sie daran, dass je höher Ihre Länge, desto langsamer folgt es, was Sie folgen wollen. Das mag nicht die meiste Zeit, aber wenn folgende Satelliten, wenn Sie langsam sind, könnte die Spur weit von der tatsächlichen Position und es wird schlecht aussehen. Sie könnten eine Lücke zwischen dem Sat und den nachfolgenden Punkten haben. Ich wählte eine Länge von 15 aktualisiert 6 mal pro Minute, um eine ausreichende Glättung und nicht zu weit von der tatsächlichen Sat-Position mit den geglätteten Spur Punkte erhalten. Antwort # 2 am: November 16, 2010, um 23:03 Uhr Initialisierung insgesamt 0, count0 (jedes Mal, wenn ein neuer Wert dann ein Eingang (scanf), ein add totalnewValue, ein Inkrement (count), ein dividieren Durchschnitt (totalcount) Dies wäre ein gleitender Durchschnitt über Alle Eingänge Um den Durchschnitt über nur die letzten 4 Eingänge zu berechnen, benötigen Sie 4 Inputvariablen, vielleicht kopieren Sie jeden Eingang zu einem älteren inputvariable und berechnen dann den neuen gleitenden Durchschnitt als Summe der 4 Inputvariablen, geteilt durch 4 (Rechtsverschiebung 2 wäre Gut, wenn alle Eingänge waren positiv, um die durchschnittliche Berechnung beantwortet werden 3. Februar um 4:06 Das wird tatsächlich berechnen den Gesamtdurchschnitt und nicht den gleitenden Durchschnitt. Wenn Zähler größer wird der Einfluss eines neuen Eingangsprobe wird verschwindend kleiner ndash Hilmar Feb Ich habe gegoogelt und keine passende oder lesbare Beispiele gefunden. Im Grunde möchte ich, um die Spur zu verfolgen Gleitenden Durchschnitt eines laufenden Stroms eines Gleitkommazahlstroms unter Verwendung der letzten 1000 Zahlen als Datenabtastwert. Was ist der einfachste Weg, um dies zu erreichen, experimentierte ich mit einem kreisförmigen Array, exponentiellen gleitenden Durchschnitt und einem einfacheren gleitenden Durchschnitt und festgestellt, dass die Ergebnisse aus dem kreisförmigen Array meine Bedürfnisse am besten geeignet. Wenn Ihre Bedürfnisse sind einfach, können Sie nur versuchen, mit einem exponentiellen gleitenden Durchschnitt. Setzen Sie einfach, Sie eine Akkumulator-Variable, und wie Ihr Code sieht auf jede Probe, aktualisiert der Code den Akkumulator mit dem neuen Wert. Sie wählen eine konstante Alpha, die zwischen 0 und 1 ist, und berechnen Sie: Sie müssen nur einen Wert von Alpha zu finden, wo die Wirkung einer gegebenen Probe nur für etwa 1000 Proben dauert. Hmm, Im nicht wirklich sicher, dass dies für Sie geeignet ist, jetzt, dass Ive es hier. Das Problem ist, dass 1000 ist ein ziemlich langes Fenster für einen exponentiellen gleitenden Durchschnitt Im nicht sicher, gibt es ein Alpha, die den Durchschnitt über die letzten 1000 Zahlen, ohne Unterlauf in der Gleitkomma Berechnung. Aber, wenn Sie einen kleineren Durchschnitt wünschen, wie 30 Zahlen oder so, dieses ist eine sehr einfache und schnelle Weise, es zu tun. Beantwortet Jun 12 12 at 4:44 1 auf Ihrem Beitrag. Der exponentielle gleitende Durchschnitt kann zulassen, dass das Alpha variabel ist. Somit kann dies dazu verwendet werden, Zeitbasisdurchschnitte (z. B. Bytes pro Sekunde) zu berechnen. Wenn die Zeit seit dem letzten Akkumulator-Update mehr als 1 Sekunde beträgt, lassen Sie Alpha 1.0 sein. Andernfalls können Sie Alpha zulassen (usecs seit letztem update1000000). Ndash jxh Grundsätzlich möchte ich den gleitenden Durchschnitt eines laufenden Stroms eines Gleitkommazahls mit den neuesten 1000 Zahlen als Datenbeispiel zu verfolgen. Beachten Sie, dass im Folgenden die Summe als Elemente als addiert ergänzt wird, wobei kostspielige O (N) - Transversionen vermieden werden, um die Summe zu berechnen, die für den durchschnittlichen Bedarf erforderlich ist. Insgesamt wird ein anderer Parameter von T gebildet, um z. B. Mit einer langen langen, wenn insgesamt 1000 lange s, eine int für char s, oder eine doppelte bis total float s. Dies ist ein wenig fehlerhaft, dass Nennsignale an INTMAX vorbeiziehen könnten - wenn Sie darauf achten, dass Sie ein langes langes nicht signiertes verwenden konnten. Oder verwenden Sie ein zusätzliches Bool-Datenelement, um aufzuzeichnen, wenn der Container zuerst gefüllt wird, während numsamples rund um das Array (am besten dann umbenannt etwas harmlos wie pos). Man nehme an, daß der quadratische Operator (T-Abtastwert) tatsächlich quadratischer Operator (T-Abtastwert) ist. Ndash oPless Jun 8 14 um 11:52 Uhr oPless ahhh. Gut beobachtet. Eigentlich meinte ich, dass es sich um void operator () (T sample) handelt, aber natürlich könntet ihr auch irgendeine Notation verwenden, die ihr mochtet. Wird beheben, danke. Ndash Tony D Jun 14 14 am 14:27


No comments:

Post a Comment