Ergebnis einer Rechenoperation auf den Wertebereich begrenzen

Gast #1293425
Lesenswert?

Hallo!

Gibt es eine einfache Möglichkeit das Ergebnis einer Rechenoperation so 
zu begrenzen das es den Wertebereich der Variable nich überschreiten 
kann?
Also z.B. bei
1
 
2
uint8_t Foo=10  
3
Foo -= 100
sollte das ergbnis 0 sein
oder bei
1
Foo *= 100
das Ergbnis 255.
Persönliche Seite #1293459
Lesenswert?

Das heisst Saturierung was sich übersetzen lässt mit Sättigung und 
ist keine Eigenschaft des Ergebnisses oder eines Wertes, sondern eines 
Operators.

Mansche Maschinen kennen Instruktionen für saturierte Operationen wie 
Addition, Subtraktion, Betrag, Shift. Oft dann in den 
Geschmacksrichtungen signed und unsigned.

Manche GCC-Versionen stellen Builtin-Funktionen dafür zur Verfügung, 
z.b. für ARM Neon.

Ansonsten muss man die "normale" Operation über einem weiteren 
Werteberech ausführen in dem kein Über/Unterlauf auftreten kann und dann 
per Vergleich bzw. Minimum/Maximum auf die gewünschten Bereich 
begrenzen.

Johann
#1293483
Lesenswert?

Johann L. schrieb:

> Ansonsten muss man die "normale" Operation über einem weiteren
> Werteberech ausführen in dem kein Über/Unterlauf auftreten kann und dann
> per Vergleich bzw. Minimum/Maximum auf die gewünschten Bereich
> begrenzen.

Wenn man eigene Funktionen schreiben muss, sollte man auch darüber 
nachdenken, ob es möglich ist vor der Operation schon vorherzusagen, ob 
das Ergebnis den Bereich verlassen wird.

Im obigen Beispiel ist das sehr leicht möglich


  uint8_t Foo=10
  if( Foo > 100 )
    Foo -= 100
  else
    Foo = 0;

Bei komplizierteren Ausdrücken, kann das natürlich entsprechend 
komplexer werden.
Persönliche Seite #1293507
Lesenswert?

Karl heinz Buchegger schrieb:
> Johann L. schrieb:
>
>> Ansonsten muss man die "normale" Operation über einem weiteren
>> Werteberech ausführen in dem kein Über/Unterlauf auftreten kann und dann
>> per Vergleich bzw. Minimum/Maximum auf die gewünschten Bereich
>> begrenzen.
>
> Wenn man eigene Funktionen schreiben muss, sollte man auch darüber
> nachdenken, ob es möglich ist vor der Operation schon vorherzusagen, ob
> das Ergebnis den Bereich verlassen wird.
>
> Im obigen Beispiel ist das sehr leicht möglich
>
>
>   uint8_t Foo=10
>   if( Foo > 100 )
>     Foo -= 100
>   else
>     Foo = 0;
>

Das tut es glaub nicht.
1
uint8_t a, b;
2
uint8_t ab = a+b;
3

4
if (ab < a)
5
  ab = 255;

und signed:
1
int8_t a, b;
2
int8_t ab = a+b;
3

4
if (b >= 0)
5
{
6
  if  (ab < a)
7
     ab = 127;
8
}
9
else
10
{
11
  if  (ab > a)
12
     ab = -128;
13
}
Persönliche Seite #1295253
Lesenswert?

Je nach Maschine/Compiler kann man zB das Carry-Flag dazu ausnutzen und 
muss nicht auf einen größeren Typen ausweichen.

Für AVR+GCC geht zum Beispiel
1
#include <stdint.h>
2

3
// unsigned saturated addition, 8 bit
4
static inline uint8_t usadd8 (uint8_t a, uint8_t b)
5
{
6
    asm  ("add %0, %1"  "\n\t"
7
          "brcc 0f"     "\n\t"
8
          "ldi %0, 255" "\n\t"
9
          "0:"
10
          : "+d" (a)
11
          : "r" (b));
12
          
13
    return a;
14
}
15

16
uint8_t add42 (uint8_t a, uint8_t b)
17
{
18
    return usadd8 (usadd8 (a, 42), b);
19
}

Der Code ist dann
1
add42:
2
  ldi r25,lo8(42)   ;  tmp46
3
  add r24, r25   ;  a, tmp46
4
  brcc 0f
5
  ldi r24, 255   ;  a
6
  0:
7
  add r24, r22   ;  a, b
8
  brcc 0f
9
  ldi r24, 255   ;  a
10
  0:
11
  ret

Johann

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren