Nun frage ich mich: soetwas ist doch vermutlich eine ziemlich oft
benötigte Funktion (implizit kommt sie in meinem Quelltext mit
unterschiedlichen Datentypen zweistellig vor und wird nur gerade in eine
einzelne Funktion pro Datentyp gebracht). Gibt es soetwas nicht schon in
der C-Standard-Library?
Viele Grüße
W.T.
Walter Tarpan schrieb:> Nun frage ich mich: soetwas ist doch vermutlich eine ziemlich oft> benötigte Funktion
In DSP-Code, Audio- und Videoverarbeitung kommt saturierende Arithmetik
oft vor, in den meisten anderen Bereichen über die Häufigkeit
ausgeführter Befehle betrachtet jedoch selten. Oft gibt es bei in diesen
Bereichen eingesetzten Prozessoren SIMD-Befehle (x86 ab MMX) für
saturierende Addition/Subtraktion und prozessorspezifische Libraries um
diese zu nutzen.
Guten Morgen,
an DSPs habe ich noch nicht einmal gedacht. Hier sind es gerade so
einfache Sachen wie "erlaubter Wertebereich in xy-Einstellungen".
Mir geht es aber auch gar nicht mal darum, das möglichst effizient oder
clever umzusetzen - die Funktionen tun das, was sie sollen und sind an
keiner Stelle, wo die Geschwindigkeit wichtig ist.
Mir geht es darum, ob ich gerade eine Standard-Library-Funktion
nachimplementiere (wobei ich mich schon ein paarmal erwischt habe, wenn
ich Wochen später zufällig auf den passenden Header gestoßen bin).
Uwe S. schrieb:> und wie behandelst Du einen Überlauf, wenn die Addition überhaupt nicht> mit 16Bit ausgeführt wird?
Sie wird hier mit mindestens 16 Bits ausgeführt.
Sind da nicht 2 Vergleiche bzw. MIN/MAX-Berechnungen überflüssig?
Etwa ist immer max <= UINT8_MAX und daher
MIN (temp, UINT8_MAX, max) = MIN (temp, max)
und analog wegen min >= 0
MAX (temp, 0, min) = MAX (temp, min)
d.h. deine Funktion macht nichts anderes als
Johann L. schrieb:> Sind da nicht 2 Vergleiche bzw. MIN/MAX-Berechnungen überflüssig?
Du hast Recht. Und der Compiler ist in dieser Frage auch deutlich
mutiger als ich vorgegangen. Ich bin bei Vergleichen Int/unsigned int
vielleicht etwas zu mißtrauisch.
Johann L. schrieb:> d.h. deine Funktion macht nichts anderes als
Da wäre ich mir an Deiner Stelle nicht so wirklich sicher. Übergib mal
( 0, -2,-2, 100)
Gaestchen schrieb:> Da wäre ich mir an Deiner Stelle nicht so wirklich sicher. Übergib mal> ( 0, -2,-2, 100)
Naja, also min > max würde ich allerdings schon als "grobe Gemeinheit"
bezeichnen.
Gaestchen schrieb:> Johann L. schrieb:>> d.h. deine Funktion macht nichts anderes als>> Da wäre ich mir an Deiner Stelle nicht so wirklich sicher. Übergib mal> ( 0, -2,-2, 100)
Wer unzulaessige Werte an eine Funktion uebergibt, der muss sich nicht
wundern wenn die Funktion nicht das macht, was man erwartet. Ganz
einfach.
Und wer bei einem Argument, das mit "uint..." deklariert ist, eine -2
uebergibt, dem ist eh nicht zu helfen.
Walter Tarpan schrieb:> Gaestchen schrieb:>> Da wäre ich mir an Deiner Stelle nicht so wirklich sicher. Übergib mal>> ( 0, -2,-2, 100)>> Naja, also min > max würde ich allerdings schon als "grobe Gemeinheit"> bezeichnen.
Zudem ist die Frage, was wäre dann eine sinnvolle Ausgabe wenn gefordert
werd, daß die Ausgabe min <= wert <= max erfüllt?
Wenn min > max dann ist wegen
max < min <= wert <= max < min
Das bedeutet dann max < max und min < min, was schwerlich zu erfüllen
ist...
Andreas Schweigstill schrieb:> Hans schrieb:>> http://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Fixed-Point.html#Fixed-Point>> Und zwar nicht erst seit GCC 4.9, sondern schon 4.6. Jedoch muss der> Compiler (und die C-Bibliothek?) mit der Option "--enable-fixed-point"> übersetzt worden sein:
Nicht unbedingt, wenn der entsprechende Support im GCC Backend aktiviert
ist, dann ist --enable-fixed-point nicht notwendig. Dies ist z.B. der
Fall ab avr-gcc 4.8
Und erst ab avr-gcc 4.8 sind einige Typen optimiert untestützt und nicht
nur durch zwar funktionierende, aber extrem ineffiziente
libgcc-Implementierungen verfügbar.
Um eine saturierende 16-Bit short Addition zu erhalten, kann man recht
umständlich:
1
#include<stdfix.h>
2
3
shortsatadd(shorta,shortb)
4
{
5
satfractfa=rbits(a);
6
satfractfb=rbits(b);
7
8
returnbitsr(fa+fb);
9
10
}
Was dann ergibt:
1
satadd:
2
addr24,r22
3
adcr25,r23
4
brvc0f
5
ldir25,0x80
6
cpr23,r25
7
sbcr24,r24
8
sbcir25,0
9
0:
10
ret
Die Saturierung ist allerding immer auf die Bitbreite des Typs; so
allgemein wie im OP mit frei wählbaren min und max ist sie nicht.
Allerdings kann sie dazu verwendet werden, in der gleichen Bitbreite zu
bleiben und nicht den nächst größeren Typ (falls es so einen gibt)
verwenden zu müssen.
Im OP liegt jedoch ein besonderer Fall von unsigned+signed vor, der
eigentlich nicht kommutativ ist:
Bei
(unsigned char) 255 + (signed char) -1
will man als Ergebnis (unsigned char) 254 haben, während es bei
(signed) -1 + (unsigned) 255
an der (signed char) Obergrenze anschlägt und das Ergebnis (signed char)
127 sein soll.
Die Fixed-Point Typen des GCC hingegen haben die gleichen Promotions von
unsigned (als Qualifier) wie int-Typen auch.