- LiTime Speicher und Akkus         
Ergebnis 1 bis 6 von 6

Thema: Integer overflow. aber wo?

  1. #1
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    34
    Beiträge
    607

    Integer overflow. aber wo?

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hallo Leute,
    ich habe hier eine Rechnung, die aufgrund eines Zahlenüberlaufs nicht richtig gerechnet wird. Aber ich kann mir einfach nicht vorstellen, wo dieser Zahlenüberlauf sein soll. Kann vielleicht jemand helfen?

    ((int32_t)((150*150)+(130*130)-(151*151)))*1024/(2*130*150)

    Ich habe extra viel Klammern gesetzt (auch unnötige), um Missverständnisse auszuschließen.

    selbst in dieser Form wird ein Integer overflow vom Compiler angezeigt (aber jetzt nur 1 mal, statt 2):
    ((int32_t)((uint16_t)(150*150)+(uint16_t)(130*130)-(uint16_t)(151*151)))*1024/(uint16_t)(2*130*150)

    Achja, ich führ die Rechnung auf einem 8bit AVR aus. Anstatt der Zahlen stehen eigentlich Variablen.

    Danke im Voraus, Yaro

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Poste einfach mal ein Stück übersetzbaren Originalcode. Da sieht man besser was geht oder nicht. Oder den Cosinussazu oder was auch immer in mehrere Teilen aufteilen.
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    34
    Beiträge
    607
    Genau, es ist der Cosinussatz! Umgeformt nach dem Winkel und mit 1024 multipliziert. Das arccos habe ich hier mal ausgelassen, da es nichts mit dem Problem zutun hat, dass es einen Integer-overflow gibt.

    Der Code (für die rechnung) sieht folgendermaßen aus:

    Code:
    char buf[7];
    uint8_t us = 150, os = 130, d123 = 151; //d123 ist eigentlich unterschiedlich, die Berechnung ist aber
    //etwas kompilzierter, und tut nix zur Sache.
    
    itoa(((int32_t)((us*us)+(os*os)-(d123*d123)))*1024/(2*us*os), buf, 10);
    
    //anschließend buf ausgeben
    Die Warnung wird meißt nur dann angezeigt, wenn man die Konstanten direkt in die Rechnung einsetzt, wenn sie als Variablen eingesetzt werden, dann gibt es (fast immer) keine Warnungen.
    Wenn ich diese Rechnung mit dem PC ausführe, dann liefert sie das richtige Ergebniss 435, mit dem AVR bekomme ich -640 bei raus.
    Ich hätte gedacht, dass das Problem ist, dass z.B. us*us größer ist, als ein signed int (16bit) speichern kann (ist es aber nicht). d123 könnte aber groß genug werden... . Wie kann ich dieses Problem beheben? habe (wie zuvor schon gepostet) auch versucht, jede einzelne Klammer in uint16_t zu casten. Hat anscheinend was gebracht, aber immer noch nicht genug. Es wird anstatt 2 overflows dann nur noch einer vom compiler angezeigt.
    Die Rechnung wird dann allerdings richtig ausgeführt (zumindest mit diesen Werten). Das Problem ist damit trotzdem nicht gelöst.

    Gruß, Yaro

  4. #4
    Benutzer Stammmitglied
    Registriert seit
    24.09.2006
    Beiträge
    84
    Hi yaro, teste doch mal ltoa() anstatt itoa(). itoa ist für Integer und der ist doch auf dem AVR nur 8 bit breit, oder?

    Hoffe das hilft

    Grüße Tobi

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Code:
    uint8_t us = 150, os = 130, d123 = 151;
    
    int32_t bar (void)
    {
        uint16_t usus = us*us;
        uint16_t osos = os*os;
        uint16_t usos = us*os;
        uint16_t d123d123 = d123*d123;
        return ((int32_t) usus+osos-d123d123)*512 / usos;
    }
    Die Quadrate werden berechnet als 8*8 = 16, denn int ist bei avr-gcc 16 Bits breit. Daher wird bei den Operationen implizit zu 16 Bits erweitert.

    Bei der 32-Bit OP muss der Cast innerhalb der Klammern stehen. Ansonsten wird mit 16 Bits gerechnet und erst danchauf 32 Bits erweitert. Die Strichrechnungen sollen aber auf 32 Bit signed erfolgen. Wenn die 2 nicht gekürzt wird, dann muss auch in den Nenner ein Cast, weil sonst das *2 auch auf 16 Bit gemacht wird. Ausserdem kann dann ein Überlauf problematisch werden, der einen positiven Wert zu einem negativen macht.

    Du hast hier 3 Effekte, die zusammenspielen:
    -- Explizite Casts
    -- Implizite Casts
    -- Übergang von Unsigned- zu Signed-Arithmetik

    Wenn du dir in Bezug auf die C-Spez nicht sicher bist, dann mach es häppchenweise und nicht in einem großen Klumbatsch. Viel Klammern helfen net viel
    Disclaimer: none. Sue me.

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    34
    Beiträge
    607
    Alles klar =)
    Das mit dem cast funktioniert jetzt auch richtig. Ich habe vorher immer angenommen, dass wenn ich eine Klammer caste, sie auch in dem Format ausgerechnet wird. Aber wenn man recht darüber nachdenkt, ist das eigentlich unlogisch.

    Ein weiteres mal vielen Dank für deine Hilfe =)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiTime Speicher und Akkus