Forum: Mikrocontroller und Digitale Elektronik 1023 * 300 = -20780.00!


von dev (Gast)


Lesenswert?

Code in C++ (AVR-GCC compiled):

int fadeDelay = abs(analogRead(fadeSpeedPotPin));
int wait = abs(fadeDelay / 25);
int hold = abs(fadeDelay * 300);

Serial.println("fadeDelay");
Serial.println(fadeDelay);

Serial.println("wait");
Serial.println(wait);

Serial.println("hold");
Serial.println(hold);

Ausgabe:

fadeDelay
1023
wait
40.00
hold
-20780.00

WTF?!

;)

von Falk B. (falk)


Lesenswert?

Integer Overflow?

von dev (Gast)


Lesenswert?

Klappt da was beim int zu String Casting in der Serial library nicht?

von dev (Gast)


Lesenswert?

Falk Brunner schrieb:
> Integer Overflow?

Deswegen hatte ich testweise nen double draus gemacht.
Mit gleichem Ergebnis.

Aber 306900 passt definitiv in ein double?!

von dev (Gast)


Lesenswert?

Again:

        int fadeDelay = abs(analogRead(fadeSpeedPotPin));

        double wait2 = abs(fadeDelay / 25);
        double hold2 = abs(fadeDelay * 300);


        Serial.println("fadeDelay");
        Serial.println(fadeDelay);
        Serial.println("wait");
        Serial.println(wait2);
        Serial.println("hold");
        Serial.println(hold2);

Ausgabe:

fadeDelay
1023
wait
40.00
hold
-20780.00


----

Aktueller Code ist definitiv auch auf dem uC übertragen.

von g457 (Gast)


Lesenswert?

> int fadeDelay = abs(analogRead(fadeSpeedPotPin));
  ^^^^^^^^^^^^^
> int wait = abs(fadeDelay / 25);
> int hold = abs(fadeDelay * 300);
                 ^^^^^^^^^   ^^^

Wie schon geschrubt wurde läuft hier die Integermultiplikation über.

von foo (Gast)


Lesenswert?

overflow bei 16bit signed integer

(1023*300 mod 2^(16)) - 2^(16) = -20780

von iTroll (Gast)


Lesenswert?

dev schrieb:
> int fadeDelay = abs(analogRead(fadeSpeedPotPin));

Wenn du fadeDelay als int deklarierst, darfst du dich nicht wundern, 
dass
1
fadeDelay * 300
einen integerüberlauf produziert

von Sam P. (Gast)


Lesenswert?

Genauer gesagt: In der double-Variante ist es auch ein Integer-Overflow, 
da durch die C-Rechenregeln erst das (overgeflowte) Endergebnis in 
double gewandelt wird.

Lösung: int32_t für alle(!) beteiligten Variablen verwenden, oder wenn 
double gewünscht wird, durch 25.0 teilen und mal 300.0, dann wird 
nämlich schon das Zwischenergebnis in Flieskomma berechnet.

von dev (Gast)


Lesenswert?

g457 schrieb:
> Wie schon geschrubt wurde läuft hier die Integermultiplikation über.

Danke, jetzt hab ichs verstanden.

Mir war nicht klar, dass der Zwischenwert also das Rechenergebnis 
genauso typsiert ist, wie die Operationsvariable und nicht wie die 
Ergebnisvariable. Ist aber klar, da die Zuweisungsoperation ja erst 
nachgelagert geschieht.

Also frei gesprochen:

1. Multiplikaton: int fadeDelay * 300 ergibt Overflow-Wert von int
2. Zuweisung: double hold2 = Overflow-Wert

So klappt es dann:

        double fadeDelay = abs(analogRead(fadeSpeedPotPin));

        wait = fadeDelay / 25;
        hold = fadeDelay * 300;


        Serial.println("fadeDelay");
        Serial.println(fadeDelay);
        Serial.println("wait");
        Serial.println(wait);
        Serial.println("hold");
        Serial.println(hold);

Randnotiz: Komme aus der dynamisch typisierten Welt :-)

von dev (Gast)


Lesenswert?

Appendix: wait und hold sind bei mir im äußeren Scope bereits als double 
deklariert.

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.