<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=91.201.66.204</id>
	<title>Mikrocontroller.net - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=91.201.66.204"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/91.201.66.204"/>
	<updated>2026-04-10T23:20:24Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_Arithmetik/Saturierung&amp;diff=52924</id>
		<title>AVR Arithmetik/Saturierung</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_Arithmetik/Saturierung&amp;diff=52924"/>
		<updated>2010-11-23T11:35:58Z</updated>

		<summary type="html">&lt;p&gt;91.201.66.204: what&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;von [[Benutzer:gjlayde|gjlayde]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Unter &#039;&#039;&#039;Saturierung&#039;&#039;&#039; (von engl. &#039;&#039;to saturate&#039;&#039;, wörtlich &#039;&#039;Sättigen&#039;&#039;) 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.&lt;br /&gt;
&lt;br /&gt;
Please visit my site:&lt;br /&gt;
http://www.pozycjonowanie-czestochowa.pl/url=187&lt;br /&gt;
 &lt;br /&gt;
http://www.pozycjonowanie-jaworzno.pl/url=447&lt;br /&gt;
&lt;br /&gt;
Regards&lt;br /&gt;
&lt;br /&gt;
== Umsetzung == &lt;br /&gt;
&lt;br /&gt;
Zur konkreten Umsetzung der Saturierung gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
;A priori: Bereits bevor das Ergebnis berechnet wurde wird anhand der Eingabe entschieden, ob der Wertebereich verlassen und ein Über- oder Unterlauf entstehen wird.&lt;br /&gt;
;A posteriori: Erst nach der Berechnung wird anhand des Ergebnisses entschieden, ob ein Über- oder Unterlauf auftrat.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Die A-posteriori-Verfahren lassen sich wiederum untergliedern in unterschiedliche Strategien, die je nach Einsatzfeld mehr oder minder effizient oder garnicht anwendbar sind:&lt;br /&gt;
&lt;br /&gt;
;Erweiterter Zahlenbereich: Die Operation wird in einem erweiterten Zahlenbereich ausgeführt in dem kein Überlauf auftreten kann. Das Ergebnis wird dann gegen die Grenzen getestet und ggf. beschnitten. Die Saturierung eines 32-Bit Wertes wird damit sehr aufwändig, weil der nächstgrößere Typ in Hochsprachen 64 Bits breit ist. Irgendwo ist eine Grenze erreicht, ab der es keinen nächstgrößeren Typ mehr gibt. Eine 8-Bit signed Saturierung könnte in C so aussehen:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
char add_signed_sat8 (char x, char y)&lt;br /&gt;
{&lt;br /&gt;
    short x_y = (short) x + y;&lt;br /&gt;
    &lt;br /&gt;
    return MAX (MIN (x_y, 127), -128);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Auswertung von Flags: Viele Rechenwerke produzieren Flags, die Auskunft über Eigenschaften des Ergebnisses enthalten. Dazu gehören Carry-, Overflow-, Negative-, Zero-Flag etc. Von einer Hochsprache aus hat man auf diese Flags keinen Zugriff, man muss also Assembler zu ihrer Auswertung heranziehen.&lt;br /&gt;
&lt;br /&gt;
;Test auf Ergebnis-Überlauf ohne Flags: Hier wird die Monotonie ausgenutzt: Falls eine positive Zahle addiert wird, so muß das Ergebnis größer werden. Falls nicht, muß ein Überlauf aufgetreten sein. Eine Formulierung in C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
char add_signed_sat8 (char x, char y)&lt;br /&gt;
{&lt;br /&gt;
    char x_y = x + y;&lt;br /&gt;
&lt;br /&gt;
    if (y &amp;gt; 0  &amp;amp;&amp;amp;  x_y &amp;lt; x)&lt;br /&gt;
        return 127;&lt;br /&gt;
&lt;br /&gt;
    if (y &amp;lt; 0  &amp;amp;&amp;amp;  x_y &amp;gt; x)&lt;br /&gt;
        return -128;&lt;br /&gt;
&lt;br /&gt;
    return x_y;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Auf AVR ===&lt;br /&gt;
&lt;br /&gt;
Saturierung ist eine Eigenschaft eines Operators und &#039;&#039;nicht&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
Angemerkt sei noch, daß in einer Hochsprache wie C auch bei Verwendung von Assembler die Portabilität erhalten bleibt, wenn maschinenabhängige Sequenzen z.&amp;amp;nbsp;B. per &amp;lt;tt&amp;gt;#ifdef&amp;lt;/tt&amp;gt; parametrisiert werden.&lt;br /&gt;
&lt;br /&gt;
==== Unsigned ====&lt;br /&gt;
&lt;br /&gt;
;Addition:&lt;br /&gt;
&lt;br /&gt;
Das ist der einfachste Fall. Die Addition zweier vorzeichenloser Zahlen liefert immer ein nicht-kleineres Ergebnis. Ein Überlauf ist am Carry erkennbar:&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R16&lt;br /&gt;
;; unsigned R0&lt;br /&gt;
;; R16 := R16 + R0 mit Saturierung&lt;br /&gt;
add  R16, R0&lt;br /&gt;
brcc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (C=1) Maximalwert laden&lt;br /&gt;
ldi  R16, 0xff    &lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als Inline-Assembler-Schnippel für avr-gcc, der in eine Inline-Funktion gefasst ist, sieht das so aus:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// x += y mit Saturierung&lt;br /&gt;
static inline uint8_t add_usat8 (uint8_t x, uint8_t y)&lt;br /&gt;
{&lt;br /&gt;
    asm (&amp;quot;add  %[x], %[y]&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;brcc 0f&amp;quot;           &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;ldi  %[x], 0xff&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;0:&amp;quot;&lt;br /&gt;
         : [x] &amp;quot;+d&amp;quot; (x)&lt;br /&gt;
         : [y] &amp;quot;r&amp;quot;  (y));&lt;br /&gt;
&lt;br /&gt;
    return x;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu beachten ist, daß x wegen dem LDI in Registerklasse &amp;lt;tt&amp;gt;&amp;quot;d&amp;quot;&amp;lt;/tt&amp;gt; (R16&amp;amp;ndash;R31) liegen muss, während für y jedes Register erlaubt ist, es also in Klasse &amp;lt;tt&amp;gt;&amp;quot;r&amp;quot;&amp;lt;/tt&amp;gt; (R0&amp;amp;ndash;R31) liegen kann.&lt;br /&gt;
&lt;br /&gt;
Ein &amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt; ist hier übrigens nicht notwendig: der Schnippel hat den Compiler nämlich bereits über &#039;&#039;alle&#039;&#039; Nebeneffekte informiert. Der Compiler darf den Schnippel (bzw. die Inline-Funktion) also wegoptmieren, wenn das Ergebnis nicht verwendet wird &amp;amp;ndash; was hier vollkommen in Ordnung ist.&lt;br /&gt;
&lt;br /&gt;
;Subtraktion:&lt;br /&gt;
&lt;br /&gt;
Ganz analog verläuft die Subtraktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R1&lt;br /&gt;
;; unsigned R0&lt;br /&gt;
;; R1 := R1 - R0 mit Saturierung&lt;br /&gt;
sub  R1, R0&lt;br /&gt;
brcc 0f&lt;br /&gt;
; Falls es einen unsigned Unterlauf gab (C=1) Minimalwert laden&lt;br /&gt;
clr  R1&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Signed ====&lt;br /&gt;
Mehr Aufwand erfordern die signed-Operatoren, weil diese in zwei Richtungen überlaufen können.&lt;br /&gt;
&lt;br /&gt;
;Addition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R16&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R16 := R16 + R0 mit Saturierung&lt;br /&gt;
add  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Maximalwert laden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Minimalwert geladen werden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Subtraktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R16&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R16 := R16 - R0 mit Saturierung&lt;br /&gt;
sub  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Minimalwert laden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Maximalwert geladen werden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Negation&lt;br /&gt;
&lt;br /&gt;
Vorsicht ist geboten beim Negieren einer Zahl und bei Betragsbildung, weil der Wert &amp;lt;tt&amp;gt;0x80&amp;lt;/tt&amp;gt;=&amp;amp;minus;128 kein positives Pendant hat:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R0 := -R0 mit Saturierung&lt;br /&gt;
neg  R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Signed Überlauf (V=1): Das Ergebnis ist 0x80 und wird verändert zu 0x7f&lt;br /&gt;
dec  R0&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Betrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R0 := Abs (R0) mit Saturierung&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
neg  R0        ; R0 &amp;lt; 0: negieren&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
dec  R0        ; R0 ist immer noch &amp;lt; 0 (also 0x80): lade 0x7f&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Unsigned + Signed ====&lt;br /&gt;
&lt;br /&gt;
Diese 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.&lt;br /&gt;
&lt;br /&gt;
;Addition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R16&lt;br /&gt;
;; signed   R0&lt;br /&gt;
;; R16 := R16 + R0 mit Saturierung&lt;br /&gt;
; Transformation [0x00, 0xff] -&amp;gt; [0x80, 0x7f]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
add  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Maximalwert laden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Minimalwert geladen werden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
0:&lt;br /&gt;
; Rücktransformation [0x80, 0x7f] -&amp;gt; [0x00, 0xff]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Subtraktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R16&lt;br /&gt;
;; signed   R0&lt;br /&gt;
;; R16 := R16 - R0 mit Saturierung&lt;br /&gt;
; Transformation [0x00, 0xff] -&amp;gt; [0x80, 0x7f]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
sub  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Minimalwert laden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Maximalwert geladen werden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
0:&lt;br /&gt;
; Rücktransformation [0x80, 0x7f] -&amp;gt; [0x00, 0xff]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
Im [[AVR-Tutorial]]:&lt;br /&gt;
* [[AVR-Tutorial: Arithmetik8|8-Bit Arithmetik]]&lt;br /&gt;
* [[AVR-Tutorial: Vergleiche|Vergleiche]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR-Arithmetik|S]]&lt;/div&gt;</summary>
		<author><name>91.201.66.204</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_Arithmetik/Saturierung&amp;diff=52890</id>
		<title>AVR Arithmetik/Saturierung</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_Arithmetik/Saturierung&amp;diff=52890"/>
		<updated>2010-11-22T15:59:36Z</updated>

		<summary type="html">&lt;p&gt;91.201.66.204: are&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;von [[Benutzer:gjlayde|gjlayde]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Unter &#039;&#039;&#039;Saturierung&#039;&#039;&#039; (von engl. &#039;&#039;to saturate&#039;&#039;, wörtlich &#039;&#039;Sättigen&#039;&#039;) 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.&lt;br /&gt;
&lt;br /&gt;
Please visit my site:&lt;br /&gt;
http://www.1katalog-stron.pl/url=124&lt;br /&gt;
 &lt;br /&gt;
http://www.2katalog-stron.pl/url=117&lt;br /&gt;
 &lt;br /&gt;
http://www.3katalog-stron.pl/url=35&lt;br /&gt;
 &lt;br /&gt;
http://4katalog-stron.pl/sitemap.html&lt;br /&gt;
 &lt;br /&gt;
http://www.4-u-katalog.pl/url=125&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Regards&lt;br /&gt;
&lt;br /&gt;
== Umsetzung == &lt;br /&gt;
&lt;br /&gt;
Zur konkreten Umsetzung der Saturierung gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
;A priori: Bereits bevor das Ergebnis berechnet wurde wird anhand der Eingabe entschieden, ob der Wertebereich verlassen und ein Über- oder Unterlauf entstehen wird.&lt;br /&gt;
;A posteriori: Erst nach der Berechnung wird anhand des Ergebnisses entschieden, ob ein Über- oder Unterlauf auftrat.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Die A-posteriori-Verfahren lassen sich wiederum untergliedern in unterschiedliche Strategien, die je nach Einsatzfeld mehr oder minder effizient oder garnicht anwendbar sind:&lt;br /&gt;
&lt;br /&gt;
;Erweiterter Zahlenbereich: Die Operation wird in einem erweiterten Zahlenbereich ausgeführt in dem kein Überlauf auftreten kann. Das Ergebnis wird dann gegen die Grenzen getestet und ggf. beschnitten. Die Saturierung eines 32-Bit Wertes wird damit sehr aufwändig, weil der nächstgrößere Typ in Hochsprachen 64 Bits breit ist. Irgendwo ist eine Grenze erreicht, ab der es keinen nächstgrößeren Typ mehr gibt. Eine 8-Bit signed Saturierung könnte in C so aussehen:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
char add_signed_sat8 (char x, char y)&lt;br /&gt;
{&lt;br /&gt;
    short x_y = (short) x + y;&lt;br /&gt;
    &lt;br /&gt;
    return MAX (MIN (x_y, 127), -128);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Auswertung von Flags: Viele Rechenwerke produzieren Flags, die Auskunft über Eigenschaften des Ergebnisses enthalten. Dazu gehören Carry-, Overflow-, Negative-, Zero-Flag etc. Von einer Hochsprache aus hat man auf diese Flags keinen Zugriff, man muss also Assembler zu ihrer Auswertung heranziehen.&lt;br /&gt;
&lt;br /&gt;
;Test auf Ergebnis-Überlauf ohne Flags: Hier wird die Monotonie ausgenutzt: Falls eine positive Zahle addiert wird, so muß das Ergebnis größer werden. Falls nicht, muß ein Überlauf aufgetreten sein. Eine Formulierung in C:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
char add_signed_sat8 (char x, char y)&lt;br /&gt;
{&lt;br /&gt;
    char x_y = x + y;&lt;br /&gt;
&lt;br /&gt;
    if (y &amp;gt; 0  &amp;amp;&amp;amp;  x_y &amp;lt; x)&lt;br /&gt;
        return 127;&lt;br /&gt;
&lt;br /&gt;
    if (y &amp;lt; 0  &amp;amp;&amp;amp;  x_y &amp;gt; x)&lt;br /&gt;
        return -128;&lt;br /&gt;
&lt;br /&gt;
    return x_y;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Auf AVR ===&lt;br /&gt;
&lt;br /&gt;
Saturierung ist eine Eigenschaft eines Operators und &#039;&#039;nicht&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
Angemerkt sei noch, daß in einer Hochsprache wie C auch bei Verwendung von Assembler die Portabilität erhalten bleibt, wenn maschinenabhängige Sequenzen z.&amp;amp;nbsp;B. per &amp;lt;tt&amp;gt;#ifdef&amp;lt;/tt&amp;gt; parametrisiert werden.&lt;br /&gt;
&lt;br /&gt;
==== Unsigned ====&lt;br /&gt;
&lt;br /&gt;
;Addition:&lt;br /&gt;
&lt;br /&gt;
Das ist der einfachste Fall. Die Addition zweier vorzeichenloser Zahlen liefert immer ein nicht-kleineres Ergebnis. Ein Überlauf ist am Carry erkennbar:&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R16&lt;br /&gt;
;; unsigned R0&lt;br /&gt;
;; R16 := R16 + R0 mit Saturierung&lt;br /&gt;
add  R16, R0&lt;br /&gt;
brcc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (C=1) Maximalwert laden&lt;br /&gt;
ldi  R16, 0xff    &lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als Inline-Assembler-Schnippel für avr-gcc, der in eine Inline-Funktion gefasst ist, sieht das so aus:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// x += y mit Saturierung&lt;br /&gt;
static inline uint8_t add_usat8 (uint8_t x, uint8_t y)&lt;br /&gt;
{&lt;br /&gt;
    asm (&amp;quot;add  %[x], %[y]&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;brcc 0f&amp;quot;           &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;ldi  %[x], 0xff&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;0:&amp;quot;&lt;br /&gt;
         : [x] &amp;quot;+d&amp;quot; (x)&lt;br /&gt;
         : [y] &amp;quot;r&amp;quot;  (y));&lt;br /&gt;
&lt;br /&gt;
    return x;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu beachten ist, daß x wegen dem LDI in Registerklasse &amp;lt;tt&amp;gt;&amp;quot;d&amp;quot;&amp;lt;/tt&amp;gt; (R16&amp;amp;ndash;R31) liegen muss, während für y jedes Register erlaubt ist, es also in Klasse &amp;lt;tt&amp;gt;&amp;quot;r&amp;quot;&amp;lt;/tt&amp;gt; (R0&amp;amp;ndash;R31) liegen kann.&lt;br /&gt;
&lt;br /&gt;
Ein &amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt; ist hier übrigens nicht notwendig: der Schnippel hat den Compiler nämlich bereits über &#039;&#039;alle&#039;&#039; Nebeneffekte informiert. Der Compiler darf den Schnippel (bzw. die Inline-Funktion) also wegoptmieren, wenn das Ergebnis nicht verwendet wird &amp;amp;ndash; was hier vollkommen in Ordnung ist.&lt;br /&gt;
&lt;br /&gt;
;Subtraktion:&lt;br /&gt;
&lt;br /&gt;
Ganz analog verläuft die Subtraktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R1&lt;br /&gt;
;; unsigned R0&lt;br /&gt;
;; R1 := R1 - R0 mit Saturierung&lt;br /&gt;
sub  R1, R0&lt;br /&gt;
brcc 0f&lt;br /&gt;
; Falls es einen unsigned Unterlauf gab (C=1) Minimalwert laden&lt;br /&gt;
clr  R1&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Signed ====&lt;br /&gt;
Mehr Aufwand erfordern die signed-Operatoren, weil diese in zwei Richtungen überlaufen können.&lt;br /&gt;
&lt;br /&gt;
;Addition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R16&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R16 := R16 + R0 mit Saturierung&lt;br /&gt;
add  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Maximalwert laden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Minimalwert geladen werden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Subtraktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R16&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R16 := R16 - R0 mit Saturierung&lt;br /&gt;
sub  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Minimalwert laden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Maximalwert geladen werden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Negation&lt;br /&gt;
&lt;br /&gt;
Vorsicht ist geboten beim Negieren einer Zahl und bei Betragsbildung, weil der Wert &amp;lt;tt&amp;gt;0x80&amp;lt;/tt&amp;gt;=&amp;amp;minus;128 kein positives Pendant hat:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R0 := -R0 mit Saturierung&lt;br /&gt;
neg  R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Signed Überlauf (V=1): Das Ergebnis ist 0x80 und wird verändert zu 0x7f&lt;br /&gt;
dec  R0&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Betrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R0 := Abs (R0) mit Saturierung&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
neg  R0        ; R0 &amp;lt; 0: negieren&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
dec  R0        ; R0 ist immer noch &amp;lt; 0 (also 0x80): lade 0x7f&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Unsigned + Signed ====&lt;br /&gt;
&lt;br /&gt;
Diese 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.&lt;br /&gt;
&lt;br /&gt;
;Addition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R16&lt;br /&gt;
;; signed   R0&lt;br /&gt;
;; R16 := R16 + R0 mit Saturierung&lt;br /&gt;
; Transformation [0x00, 0xff] -&amp;gt; [0x80, 0x7f]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
add  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Maximalwert laden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Minimalwert geladen werden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
0:&lt;br /&gt;
; Rücktransformation [0x80, 0x7f] -&amp;gt; [0x00, 0xff]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Subtraktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R16&lt;br /&gt;
;; signed   R0&lt;br /&gt;
;; R16 := R16 - R0 mit Saturierung&lt;br /&gt;
; Transformation [0x00, 0xff] -&amp;gt; [0x80, 0x7f]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
sub  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Minimalwert laden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Maximalwert geladen werden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
0:&lt;br /&gt;
; Rücktransformation [0x80, 0x7f] -&amp;gt; [0x00, 0xff]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
Im [[AVR-Tutorial]]:&lt;br /&gt;
* [[AVR-Tutorial: Arithmetik8|8-Bit Arithmetik]]&lt;br /&gt;
* [[AVR-Tutorial: Vergleiche|Vergleiche]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR-Arithmetik|S]]&lt;/div&gt;</summary>
		<author><name>91.201.66.204</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_Arithmetik/Saturierung&amp;diff=52731</id>
		<title>AVR Arithmetik/Saturierung</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_Arithmetik/Saturierung&amp;diff=52731"/>
		<updated>2010-11-13T06:44:11Z</updated>

		<summary type="html">&lt;p&gt;91.201.66.204: Health&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;von [[Benutzer:gjlayde|gjlayde]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Unter &#039;&#039;&#039;Saturierung&#039;&#039;&#039; (von engl. &#039;&#039;to saturate&#039;&#039;, wörtlich &#039;&#039;Sättigen&#039;&#039;) 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.&lt;br /&gt;
&lt;br /&gt;
Please visit my &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Regards&lt;br /&gt;
&lt;br /&gt;
== Umsetzung == &lt;br /&gt;
&lt;br /&gt;
Zur konkreten Umsetzung der Saturierung gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
;A priori: Bereits bevor das Ergebnis berechnet wurde wird anhand der Eingabe entschieden, ob der Wertebereich verlassen und ein Über- oder Unterlauf entstehen wird.&lt;br /&gt;
;A posteriori: Erst nach der Berechnung wird anhand des Ergebnisses entschieden, ob ein Über- oder Unterlauf auftrat.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Die A-posteriori-Verfahren lassen sich wiederum untergliedern in unterschiedliche Strategien, die je nach Einsatzfeld mehr oder minder effizient oder garnicht anwendbar sind:&lt;br /&gt;
&lt;br /&gt;
;Erweiterter Zahlenbereich: Die Operation wird in einem erweiterten Zahlenbereich ausgeführt in dem kein Überlauf auftreten kann. Das Ergebnis wird dann gegen die Grenzen getestet und ggf. beschnitten. Die Saturierung eines 32-Bit Wertes wird damit sehr aufwändig, weil der nächstgrößere Typ in Hochsprachen 64 Bits breit ist. Irgendwo ist eine Grenze erreicht, ab der es keinen nächstgrößeren Typ mehr gibt. Eine 8-Bit signed Saturierung könnte in C so aussehen:&lt;br /&gt;
:{|&lt;br /&gt;
|&amp;lt;c&amp;gt;&lt;br /&gt;
char add_signed_sat8 (char x, char y)&lt;br /&gt;
{&lt;br /&gt;
    short x_y = (short) x + y;&lt;br /&gt;
    &lt;br /&gt;
    return MAX (MIN (x_y, 127), -128);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Auswertung von Flags: Viele Rechenwerke produzieren Flags, die Auskunft über Eigenschaften des Ergebnisses enthalten. Dazu gehören Carry-, Overflow-, Negative-, Zero-Flag etc. Von einer Hochsprache aus hat man auf diese Flags keinen Zugriff, man muss also Assembler zu ihrer Auswertung heranziehen.&lt;br /&gt;
&lt;br /&gt;
;Test auf Ergebnis-Überlauf ohne Flags: Hier wird die Monotonie ausgenutzt: Falls eine positive Zahle addiert wird, so muß das Ergebnis größer werden. Falls nicht, muß ein Überlauf aufgetreten sein. Eine Formulierung in C:&lt;br /&gt;
:{|&lt;br /&gt;
|&amp;lt;c&amp;gt;&lt;br /&gt;
char add_signed_sat8 (char x, char y)&lt;br /&gt;
{&lt;br /&gt;
    char x_y = x + y;&lt;br /&gt;
&lt;br /&gt;
    if (y &amp;gt; 0  &amp;amp;&amp;amp;  x_y &amp;lt; x)&lt;br /&gt;
        return 127;&lt;br /&gt;
&lt;br /&gt;
    if (y &amp;lt; 0  &amp;amp;&amp;amp;  x_y &amp;gt; x)&lt;br /&gt;
        return -128;&lt;br /&gt;
&lt;br /&gt;
    return x_y;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Auf AVR ===&lt;br /&gt;
&lt;br /&gt;
Saturierung ist eine Eigenschaft eines Operators und &#039;&#039;nicht&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
Angemerkt sei noch, daß in einer Hochsprache wie C auch bei Verwendung von Assembler die Portabilität erhalten bleibt, wenn maschinenabhängige Sequenzen z.&amp;amp;nbsp;B. per &amp;lt;tt&amp;gt;#ifdef&amp;lt;/tt&amp;gt; parametrisiert werden.&lt;br /&gt;
&lt;br /&gt;
==== Unsigned ====&lt;br /&gt;
&lt;br /&gt;
;Addition:&lt;br /&gt;
&lt;br /&gt;
Das ist der einfachste Fall. Die Addition zweier vorzeichenloser Zahlen liefert immer ein nicht-kleineres Ergebnis. Ein Überlauf ist am Carry erkennbar:&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R16&lt;br /&gt;
;; unsigned R0&lt;br /&gt;
;; R16 := R16 + R0 mit Saturierung&lt;br /&gt;
add  R16, R0&lt;br /&gt;
brcc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (C=1) Maximalwert laden&lt;br /&gt;
ldi  R16, 0xff    &lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als Inline-Assembler-Schnippel für avr-gcc, der in eine Inline-Funktion gefasst ist, sieht das so aus:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// x += y mit Saturierung&lt;br /&gt;
static inline uint8_t add_usat8 (uint8_t x, uint8_t y)&lt;br /&gt;
{&lt;br /&gt;
    asm (&amp;quot;add  %[x], %[y]&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;brcc 0f&amp;quot;           &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;ldi  %[x], 0xff&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;0:&amp;quot;&lt;br /&gt;
         : [x] &amp;quot;+d&amp;quot; (x)&lt;br /&gt;
         : [y] &amp;quot;r&amp;quot;  (y));&lt;br /&gt;
&lt;br /&gt;
    return x;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu beachten ist, daß x wegen dem LDI in Registerklasse &amp;lt;tt&amp;gt;&amp;quot;d&amp;quot;&amp;lt;/tt&amp;gt; (R16&amp;amp;ndash;R31) liegen muss, während für y jedes Register erlaubt ist, es also in Klasse &amp;lt;tt&amp;gt;&amp;quot;r&amp;quot;&amp;lt;/tt&amp;gt; (R0&amp;amp;ndash;R31) liegen kann.&lt;br /&gt;
&lt;br /&gt;
Ein &amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt; ist hier übrigens nicht notwendig: der Schnippel hat den Compiler nämlich bereits über &#039;&#039;alle&#039;&#039; Nebeneffekte informiert. Der Compiler darf den Schnippel (bzw. die Inline-Funktion) also wegoptmieren, wenn das Ergebnis nicht verwendet wird &amp;amp;ndash; was hier vollkommen in Ordnung ist.&lt;br /&gt;
&lt;br /&gt;
;Subtraktion:&lt;br /&gt;
&lt;br /&gt;
Ganz analog verläuft die Subtraktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R1&lt;br /&gt;
;; unsigned R0&lt;br /&gt;
;; R1 := R1 - R0 mit Saturierung&lt;br /&gt;
sub  R1, R0&lt;br /&gt;
brcc 0f&lt;br /&gt;
; Falls es einen unsigned Unterlauf gab (C=1) Minimalwert laden&lt;br /&gt;
clr  R1&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Signed ====&lt;br /&gt;
Mehr Aufwand erfordern die signed-Operatoren, weil diese in zwei Richtungen überlaufen können.&lt;br /&gt;
&lt;br /&gt;
;Addition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R16&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R16 := R16 + R0 mit Saturierung&lt;br /&gt;
add  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Maximalwert laden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Minimalwert geladen werden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Subtraktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R16&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R16 := R16 - R0 mit Saturierung&lt;br /&gt;
sub  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Minimalwert laden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Maximalwert geladen werden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Negation&lt;br /&gt;
&lt;br /&gt;
Vorsicht ist geboten beim Negieren einer Zahl und bei Betragsbildung, weil der Wert &amp;lt;tt&amp;gt;0x80&amp;lt;/tt&amp;gt;=&amp;amp;minus;128 kein positives Pendant hat:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R0 := -R0 mit Saturierung&lt;br /&gt;
neg  R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Signed Überlauf (V=1): Das Ergebnis ist 0x80 und wird verändert zu 0x7f&lt;br /&gt;
dec  R0&lt;br /&gt;
0:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Betrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; signed R0&lt;br /&gt;
;; R0 := Abs (R0) mit Saturierung&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
neg  R0        ; R0 &amp;lt; 0: negieren&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
dec  R0        ; R0 ist immer noch &amp;lt; 0 (also 0x80): lade 0x7f&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Unsigned + Signed ====&lt;br /&gt;
&lt;br /&gt;
Diese 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.&lt;br /&gt;
&lt;br /&gt;
;Addition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R16&lt;br /&gt;
;; signed   R0&lt;br /&gt;
;; R16 := R16 + R0 mit Saturierung&lt;br /&gt;
; Transformation [0x00, 0xff] -&amp;gt; [0x80, 0x7f]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
add  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Maximalwert laden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Minimalwert geladen werden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
0:&lt;br /&gt;
; Rücktransformation [0x80, 0x7f] -&amp;gt; [0x00, 0xff]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Subtraktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
;; unsigned R16&lt;br /&gt;
;; signed   R0&lt;br /&gt;
;; R16 := R16 - R0 mit Saturierung&lt;br /&gt;
; Transformation [0x00, 0xff] -&amp;gt; [0x80, 0x7f]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
sub  R16, R0&lt;br /&gt;
brvc 0f&lt;br /&gt;
; Falls es einen signed Überlauf gab (V=1) Minimalwert laden&lt;br /&gt;
ldi  R16, 0x80&lt;br /&gt;
sbrc R0, 7&lt;br /&gt;
; R0 ist negativ, daher muss der Maximalwert geladen werden&lt;br /&gt;
ldi  R16, 0x7f&lt;br /&gt;
0:&lt;br /&gt;
; Rücktransformation [0x80, 0x7f] -&amp;gt; [0x00, 0xff]&lt;br /&gt;
subi R16, 0x80&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
Im [[AVR-Tutorial]]:&lt;br /&gt;
* [[AVR-Tutorial: Arithmetik8|8-Bit Arithmetik]]&lt;br /&gt;
* [[AVR-Tutorial: Vergleiche|Vergleiche]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR-Arithmetik|S]]&lt;/div&gt;</summary>
		<author><name>91.201.66.204</name></author>
	</entry>
</feed>