Berechnung von uint8_t ohne Überlauf

OP #4414207
Hallo,

ich hätte eine kurze Frage
1
    rgb[0].r = (uint16_t)((val * color->r) / 255); 
2
    rgb[0].g =  (uint16_t)((val * color->g) / 255); 
3
    rgb[0].b =  (uint16_t)((val * color->b) / 255);

Bei dieser Berechnung kann der Wert zwischenzeitglich größer 255 (1 
Byte) werden. Ist das uint16_t so richtig angewendet?
rgb[0].r, g, b sind jeweils uint8_t

Desweiteren wäre es sinnvoller, das ganze anstatt mit "/ 255" besser mit 
>> 7 zu machen?
Gast #4414211
>Bei dieser Berechnung kann der Wert zwischenzeitglich größer 255 (1
>Byte) werden. Ist das uint16_t so richtig angewendet?

Nein.

>Desweiteren wäre es sinnvoller, das ganze anstatt mit "/ 255" besser mit
>>> 7 zu machen?

>>7 bedeutet /128. Ob das besser ist? Und wieso teilst du nicht durch 256?
Nur dann könnte man schieben.
OP #4414221
Wie ist das nein zu deuten? Das der Wert im Endeffekt nicht größer als 
255 wird, ist klar. Das liegt aber auch nur daran dass zum einen es das 
Endergebnis nicht zulässt, zum anderen aber auch, da es zum Überlauf 
kommt.

Wo muss ich ggf. das (uint16_t) setzen?
_r = ((uint16_t)val * r) / 255

Durch 256 teilen macht eigentlich doch wenig Sinn, dann gibt es den 
vollen Ausschlag (255) nicht mehr. Spielt hier auch eher weniger die 
Rolle, der Unterschied ist um 1 spielt keine Rolle. Ist das Shiften hier 
deutlich effizienter? Im Einsatz ist ein Atiny841
#4414222
Stefan S. schrieb:
> Ist das uint16_t so richtig angewendet?

In deinem ersten Beispiel hast du das Ergebnis der Multiplikation 
gecastet, nicht die Operanden der Multiplikation, so wie in deinem 
zweiten Beispiel.

Der Standard verlangt, dass in mindestens 16Bit (Mindestgrösse int) 
gerechnet wird (in deinem Fall in signed). Wenn du in unsigned rechnen 
willst, musst du einen der Operanden nach unsigned (hier uint16_t) 
casten. Ist ein int grösser, z.B. 32Bit, spielt es in deinem Falle keine 
Rolle, ob du in signed oder unsigned rechnest. Ich würde den Cast 
jedenfalls drinlassen, da er aussagt, dass du mindestens in 16Bit 
unsigned rechnen willst.

Edit: Ich habe die Annahme gemacht, dass deine beiden Operatoren vom Typ 
uint8_t sind.
Gast #4414223
Genau genommen, kommt es auf den Compiler an.

Nach C Standard muss der Compiler zuerst nach Integer konvertieren und 
dann alles mit Integer rechnen - der Cast wäre überflüssig.

Compiler für Mikrocontroller rechnen normalerweise entgegen dem 
C-Standard mit 8Bit Zahlen und 8Bit Ergebnis. Du musst als allererstes 
einen der 8Bit Werte auf 16Bit casten. Dann rechnet der Compiler mit 
16Bit = (16Bit * 16Bit) / 16Bit.

rgb[0].r = ((((uint16_t)val) * color->r) / 255);

(Eigentlich recht unsinnig. Viele Mikrocontroller haben Hardware, die 
16Bit = 8Bit * 8Bit sehr schnell berechnen kann.)

Ob du /256 oder >>8 schreibst? Eigentlich egal - die Optimizer sind so 
gut, machen sowieso das selbe daraus. Wenn du eine 100% sichere Antwort 
haben willst - vom Compiler ein Assembler-Listing ausgeben lassen.
#4414224
Stefan S. schrieb:
> Ist das Shiften hier
> deutlich effizienter? Im Einsatz ist ein Atiny841

Wenn du nach unsigned castest, wird der Compiler die Division 
automatisch durch einen Shift ersetzen (nur bei 2er-Potenzen). Wir 
hatten ein ähnliches Thema letztens hier im Forum (signed vs. unsigned 
beim Shiften):
Beitrag "Re: Einstieg in C - komische Fragen"

Edit: Habs gerade durch den Compiler gejagt, er nimmt nach der 
Multiplikation einfach das höherwertige Byte und verwirft den Rest.
1
A = ((uint16_t)B * C) / 256;

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.