Überlauferkennung mit C18

Ich implementiere einen Taschenrechner in einem Mikrocontroller, der über die serielle Schnittstelle gesteuert wird. Zum Beispiel würde ich senden 1234*5678=und es würde mit antworten 7006652\r\n. Ich habe den Code dafür mit dem C18-Compiler geschrieben.

Wenn ich sende 123456*789123=, bekomme ich die Antwort 2932688576, die falsch ist. Die richtige Antwort wäre gewesen 97421969088, aber das läuft einem über unsigned long.

Ich möchte das Überlauflimit nicht erhöhen, aber ich hätte gerne eine Möglichkeit zu überprüfen, ob es einen Überlauf gegeben hat. In ASM wäre das möglich, indem das entsprechende Bit im STATUS-Register überprüft wird, aber mit C würde dieses Bit gelöscht, bevor ich es lesen könnte, oder?

Am besten wäre eine allgemeine Lösung, um zu sehen, ob ein Überlauf aufgetreten ist.

Eine naheliegende Möglichkeit wäre die Verwendung von Ada, zB Gnat mit eingeschalteten Überlaufprüfungen. Leider sollte das zwar mit AVR oder MSP430 oder ARM funktionieren, aber ich kenne keinen geeigneten Compiler für PIC.
Ich hatte das Gefühl, dass dies eher eine Stackoverflow.com-Frage sein könnte, und tatsächlich führte mich eine Suche direkt dorthin. Nach einiger Lektüre kam ich zu dem Schluss, dass es darauf keine einfache Antwort gibt (jedenfalls mit C).
@gbarry kannst du mir einen Link zu der relevanten SO-Frage geben?
Ich habe nach "Algorithm Check Overflow" gesucht und Folgendes erhalten: stackoverflow.com/questions/2713972 Und der erste Kommentar war ein Link zu einer ähnlichen Frage ... stackoverflow.com/questions/199333

Antworten (2)

Es mag Tricks in Bezug auf das STATUS-Register geben, aber der folgende generische (ungetestete) Code ist etwas, an das ich gedacht habe, um die Anzahl der Bits zu überprüfen, die zur Darstellung jedes Eingangs erforderlich sind, indem wiederholte Bitverschiebungsoperationen nach rechts durchgeführt werden, bis der Wert leer ist.

Wenn Sie dann die beiden Ergebnisse addieren, sollten Sie in der Lage sein, herauszufinden, ob die Ausgabe 32 Bit überläuft.

unsigned long a = 123456;
unsigned long b = 789123;

int calc_bit_size(unsigned long v)
{
    int bit_count = 0;
    while (v > 0)
    {
        bit_count++;
        v >>= 1;
    }
    return bit_count;
}

if (calc_bit_size(a) + calc_bit_size(b) > 32)
   printf("Overflow!")
else
   printf("%lu", a * b);

Lassen Sie das interne Ergebnis einfach so breit sein wie die Summe der Breite der Operanden, und prüfen Sie dann, ob das Ergebnis nicht höher als extern zulässig war. Wenn der PIC18 einen Hardware-Multiplikator hat, ist dies nicht wirklich rechenintensiv und völlig genau, im Gegensatz zu dem Verfahren zur Bestimmung der Summe der Position der höchstwertigen Nicht-Null-Ziffer der Operanden.

Siehe Seite 174 des Dokuments in http://ptgmedia.pearsoncmg.com/images/0321335724/samplechapter/seacord_ch05.pdf

PIC18 verfügt über einen 8-Bit-Hardware-Multiplikator, sodass Multiplikationen bei größeren Zahlen "angemessen" schnell sind.