|
|
AVR Arithmetik/Saturierungvon gjlayde Unter Saturierung (von engl. to saturate, wörtlich Sättigen) versteht man die Eigenschaft bestimmter Operatoren, bei Überschreitung der Bereichs-Grenzen den Maximal- bzw. Minimalwert zu liefern, anstatt überzulaufen und einen Wert zu liefen, der sehr weit vom erwarteten Ergebnis entfernt liegt.
[Bearbeiten] EinleitungBei vielen Anwendungen wie der digitalen Signalverarbeitung ist es wichtig, daß ein Wert an den Rändern seines Wertebereiches nicht überläuft. Ist eine Größe x zum Beispiel als 8-Bit Wert mit Vorzeichen gespeichert, so führt die Operation
zum Ergebnis y=−128. Solch ein riesiger Sprung ist in vielen Anwendungen fatal. Anstatt an den Bereichsgrenzen überzulaufen ist dann erforderlich daß der Wert an der Maximalgrenze stehen bleibt, d.h. daß das Ergebnis in dem Falle y=127 ist anstatt −128. Die Variable kann ab dieser Grenze nichts mehr aufnehmen: sie hat ihre "Sättigung" erreicht. Um saturierte Addition von der üblichen Addition zu unterscheiden, wird hier das Symbol Eine saturierte Addition hat eine sehr wichtige Eigenschaft der gewohnten Addition, nämlich die Monotonie: Analoge Zusammenhänge gibt es für die Monotonie der (saturierten) Subtraktion sowie für andere saturierte Operatoren wie Negation, Betragsbildung, Multiplikation und Division, welche die gleichen Monotonie-Eigenschaften haben wie die "nativen" mathematischen Operatoren. Durch Zugewinn der Monotonie verliert man allerdings die Assoziativität, so daß die Reihenfolge, in der saturierte Operatoren anwandt werden, wie im folgenden Beispiel einen Einfluß auf das Ergebnis haben kann: Das ist bei Verwendung von saturierten Operatoren immer zu bedenken! Neber der Saturierung, welche bei den Werte an den Bereichsgrenzen – also dort, wo ein Überlauf stattfinden würde – stehen bleibt, gibt es auch Saturierungen, die zB auf den Wertebereich −100...100 begrenzen. Letztere lässt sich zusammensetzen aus einer "normalen" Saturierung, wie sie hier im weiteren besprochen wird, und einer Maximum- bzw. Minimum-Bildung gegen den gewünschten Wertebereich. [Bearbeiten] UmsetzungZur konkreten Umsetzung der Saturierung gibt es mehrere Möglichkeiten:
Sind vorzeichenbehaftete Operanden beteiligt, so fällt die Entscheidung strenggenommen automatisch zugunsten der a priori-Variante aus: In C führt der Überlauf von vorzeichenbehafteten Zahlen explizit zu undefiniertem Verhalten; es steht dem Compiler frei, in einem solchen Fall Instruktionen zu generieren, die beispielsweise den Prozessor anhalten oder neustarten. Am gebräuchlichsten und effizientesten für kleine Typen sind (wenn möglich) A-posteriori-Methoden, da hier das Ergebnis als Entscheidungsgrundlage mit einbezogen werden kann. Das Ergebnis wird unbedingt berechnet und im Fall eines Überlaufs wieder verworfen. Dieser Mehraufwand muss bei aufwändigen Operatoren mit dem Aufwand von a-priori-Methoden abgewogen werden. Die A-posteriori-Verfahren lassen sich wiederum untergliedern in unterschiedliche Strategien, die je nach Einsatzfeld mehr oder minder effizient oder garnicht anwendbar sind:
[Bearbeiten] Auf AVRSaturierung ist eine Eigenschaft eines Operators und nicht die einer Zahl, wie bei unsigned/signed, welche nur von der Interpretation des Ergebnisses abhängt. Während für signed/unsigned-Addition die gleichen Befehle verwendet werden, ist dies bei Saturierung nicht der Fall, und wir müssen unterscheiden zwischen verschiedenen Ausprägungen der Saturierung, was in unterschiedlichen Implementierungen resultiert. Wie im vorhergehenden Abschitt zu sehen, kann Saturierung im Vergleich zu einer gewohnten Addition, die in einem Maschinenbefehl umsetzbar ist, sehr aufwändig sein. Daher versuchen wir nach Möglichkeit Status-Flags des AVR zu verwenden, um einen Überlauf zu erkennen. Dies ist von einer Hochsprache aus leider nicht möglich, so daß wir auf (Inline-)Assembler zurückgreifen müssen, um eine effiziente Implementierung zu erhalten. Angemerkt sei noch, daß in einer Hochsprache wie C auch bei Verwendung von Assembler die Portabilität erhalten bleibt, wenn maschinenabhängige Sequenzen z. B. per #ifdef parametrisiert werden. [Bearbeiten] Unsigned
Das ist der einfachste Fall. Die Addition zweier vorzeichenloser Zahlen liefert immer ein nicht-kleineres Ergebnis. Ein Überlauf ist am Carry erkennbar:
Als Inline-Assembler-Schnippel für avr-gcc, der in eine Inline-Funktion gefasst ist, sieht das so aus:
Zu beachten ist, daß x wegen dem LDI in Registerklasse "d" (R16–R31) liegen muss, während für y jedes Register erlaubt ist, es also in Klasse "r" (R0–R31) liegen kann. Ein volatile ist hier übrigens nicht notwendig: der Schnippel hat den Compiler nämlich bereits über alle Nebeneffekte informiert. Der Compiler darf den Schnippel (bzw. die Inline-Funktion) also wegoptmieren, wenn das Ergebnis nicht verwendet wird – was hier vollkommen in Ordnung ist.
Ganz analog verläuft die Subtraktion:
[Bearbeiten] SignedMehr Aufwand erfordern die signed-Operatoren, weil diese in zwei Richtungen überlaufen können.
Vorsicht ist geboten beim Negieren einer Zahl und bei Betragsbildung, weil der Wert 0x80=−128 kein positives Pendant hat:
[Bearbeiten] Unsigned + SignedDiese Kombination ist am aufwändigsten in der Behandlung und geschieht am einfachsten durch Umskalierung auf zwei signed-Werte, signed-saturierter Operation und nachfolgender Rückskalierung. Zu beachten ist, daß dieser Operator nicht kommutativ ist, d.h. a+b liefert i.A. ein anderes Ergebnis als b+a.
[Bearbeiten] Siehe auchIm AVR-Tutorial: |