Forum: Mikrocontroller und Digitale Elektronik Integer Overflow


von Schorschi (Gast)


Lesenswert?

Hallo zusammen,

Mal eine Frage an euch C cracks über integer overflows. Man nehme 
folgendes Beispiel an:
1
static uint16_t top_value = 6249;
2
3
void pwm_set(uint8_t value) {
4
  value = (value > 100) ? (100) : (value);
5
  
6
  // 1. Möglichkeit
7
  uint16_t cmp = (top_value * value) / 100;
8
9
  // 2. Möglichkeit
10
  uint16_t cmp = top_value / 100 * value;
11
}

Aus meiner Sicht wäre in der ersten Möglichkeit ein Overflow, falls der 
value z.B. 100 ist. Handelt dass der Compiler, oder muss ich da selber 
auf die zweite Möglichkeit ausweichen? Die Erste würde mir besser 
gefallen, da dann kein (oder ein viel kleinerer) Rundungsfehler 
entsteht.

von Oliver S. (oliverso)


Lesenswert?

Schorschi schrieb:
> Handelt dass der Compiler,

Der Compiler nicht, aber der C-Standard.

Oliver

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ist die Frage, wie groß ein "int" auf deiner Maschine ist.

Ist es nur 16 Bit (bpsw. AVR), dann macht der Compiler nichts, um dem 
Overflow zu entgegnen. Du müsstest dort manuell einen der beiden 
Elemente der Multiplikatiion auf "unsigned int" casten.

Ist es 32 Bit (bspw. ARM), dann würden die Operanden implizit nach "int" 
konvertiert. Dann passt alles.

Deine zweite Variante ist natürlich suboptimal; dann könntest du auch 
gleich den Top-Wert durch 100 teilen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Schorschi schrieb:
> muss ich da selber auf die zweite Möglichkeit ausweichen?
Ich würde die Rechnung einfach in 32 Bit machen, und dann vom Ergebnis 
nur 16 Bit verwenden:
uint16_t cmp = (uint32_t)top_value*value / 100;

: Bearbeitet durch Moderator
von Theor (Gast)


Lesenswert?

Ich schlage vor, falls es um einen AVR geht, und der Compiler GCC ist, 
auf 32 Bit zu casten.
Denn dezimal 6294 hat schon 13 Bit und die Multiplikation mit dezimal 
100 (7 Bit) oder sogar dezimal 255 (8 Bit) ergibt dann 20 bwz. 21 Bit.
unsigned int hat, soweit ich weiß, hingegen nur 16 Bit.

von Schorschi (Gast)


Lesenswert?

Hallo und vielen Dak erst mal!

Ja, es geht um einen AVR. Ich werde dann wohl die cast Methode nehmen!
Danke und Gruss

von sid (Gast)


Lesenswert?

Jörg W. schrieb:
> Deine zweite Variante ist natürlich suboptimal; dann könntest du auch
> gleich den Top-Wert durch 100 teilen.


Jo..

ooder durch zehn ;) dann ist der Rundungsfehler (value/100)
und der maximalwert 62500 (also innerhalb 16bit)

cmd = (625*value)/10
oder wenn der Rundungsfehler inakzeptabel scheint (ist ja nie grösser 
als 1!)
und da wir ja von integern reden.... zu vernachlässigen IMHO...
egal falls Deiner Meinung nach nicht:
cmd = (625*value)/10 - value/100

(lass mal den controller beides nebeneinander herrechnen, alle werte 
zwischen 1 und 100 ... ich denke es wird keinen Unterschied machen 
#schulterzuck

'sid

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

sid schrieb:
> ich denke es wird keinen Unterschied machen #schulterzuck
Bestenfalls bei der Laufzeit... ;-)

Und dann könnte man noch weiter optimieren und das Ganze auf eine 16er 
Basis stellen, so dass man mit einer Multiplikation auskommt und gar 
nicht teilen muss, sondern nur die unteren 16 Bit abschneidet:
1
  cmp = (6249 * value) / 100;
2
3
                         // den Bruch mit "65536/100" erweitern
4
      = (6249 * value * 65536/100) / (100 * 65536/100); 
5
                                      
6
                         // Unsortieren
7
      = (6249 * 65536/100 * value ) / (100/100 * 65536)
8
   
9
                         // Division durch "Shift" ersetzen
10
      = (6249 * 65536/100 * value) >> 16;
11
12
                         // nichts für schwache Nerven: Magic Number
13
      = (4095344 * value) >> 16;
Und voila: wie versprochen ist von der Division nur eine Multiplikation 
übrig... ;-)

BTW: klar, dass man in den obigen Zwischenschritten für ein korrektes 
ergebnis hie und da noch ein UL anfügen sollte.

: Bearbeitet durch Moderator
von sid (Gast)


Lesenswert?

Lothar M. schrieb:
> Bestenfalls bei der Laufzeit... ;-)

Touché!

'sid

von Sven B. (scummos)


Angehängte Dateien:

Lesenswert?

Lothar M. schrieb:
> Und voila: wie versprochen ist von der Division nur eine Multiplikation
> übrig... ;-)

Ohne konkreten Bedarf würde ich sowas ja dem Compiler überlassen ;)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.