Überlauf mit C18 erkennen

7

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=, erhalte ich die Antwort 2932688576, die falsch ist. Die richtige Antwort wäre gewesen 97421969088, aber das läuft über unsigned long.

Ich möchte das Überlauflimit nicht erhöhen, möchte aber eine Möglichkeit haben, zu überprüfen, ob ein Überlauf aufgetreten ist. In ASM wäre dies möglich, indem das relevante Bit im STATUS-Register überprüft wird. Mit C würde dieses Bit jedoch gelöscht, bevor ich es lesen könnte, nicht wahr?

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


quelle
Ein naheliegender Weg wäre die Verwendung von Ada, z. B. Gnat mit eingeschalteten Überlaufprüfungen. Obwohl dies mit AVR oder MSP430 oder ARM funktionieren sollte, kenne ich leider keinen geeigneten Compiler für PIC.
Brian Drummond
Ich ahnte, dass dies eher eine Frage von stackoverflow.com sein könnte, und tatsächlich führte mich eine Suche direkt dorthin. Nach einigem Lesen kam ich zu dem Schluss, dass es keine einfache Antwort darauf gibt (jedenfalls mit C).
Gbarry
@gbarry Kannst du mir einen Link zu der relevanten SO-Frage geben?
1
Ich suchte nach "Algorithmus Check Overflow" und bekam dies: stackoverflow.com/questions/2713972 Und der erste Kommentar war ein Link zu einer ähnlichen Frage ... stackoverflow.com/questions/199333
gbarry

Antworten:

3

Es mag Tricks bezüglich des STATUS-Registers geben, aber der folgende generische (nicht getestete) Code ist etwas, an das ich gedacht habe, um die Anzahl der Bits zu überprüfen, die zur Darstellung jeder Eingabe erforderlich sind, indem wiederholte Rechtsbitverschiebungsoperationen ausgefü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);
PeterJ
quelle
2

Lassen Sie das interne Ergebnis einfach so breit sein wie die Summe der Breite der Operanden, und überprüfen Sie dann, ob das Ergebnis nicht höher als extern zulässig war. Wenn der PIC18 über einen Hardware-Multiplikator verfügt, ist dieser nicht wirklich rechenintensiv und im Gegensatz zu der Methode zur Bestimmung der Summe der Position der höchstwertigen Nicht-Null-Ziffer der Operanden vollständig genau.

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

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