7
\$\begingroup\$

I'm implementing a calculator in a microcontroller which is controlled over the serial port. For example, I'd send 1234*5678= and it would reply with 7006652\r\n. I've written the code for this using the C18 compiler.

When I send 123456*789123=, I get the reply 2932688576, which is incorrect. The correct answer would have been 97421969088, but that overflows an unsigned long.

I do not want to increase the overflow limit, but would like to have a way to check if there has been an overflow. In ASM, that would be possible by checking the relevant bit in the STATUS register, however, with C, this bit would be cleared before I could read it, wouldn't it?

The best would be a general solution to see if an overflow has occured.

\$\endgroup\$
  • \$\begingroup\$ One obvious way would be to use Ada, e.g. Gnat with the overflow checks switched on. Unfortunately, while that should work with AVR or MSP430 or ARM, I don't know of a suitable compiler for PIC. \$\endgroup\$ – Brian Drummond Apr 13 '13 at 16:11
  • \$\begingroup\$ I sensed this might be more like a stackoverflow.com question, and sure enough, a search took me straight there. I concluded, after some reading, that there is no simple answer to this (using C, anyway). \$\endgroup\$ – gbarry Apr 14 '13 at 6:21
  • \$\begingroup\$ @gbarry can you give me a link to the relevant SO question? \$\endgroup\$ – user17592 Apr 14 '13 at 6:28
  • 1
    \$\begingroup\$ I searched on "algorithm check overflow" and got this: stackoverflow.com/questions/2713972 And the first comment was a link to a similar question... stackoverflow.com/questions/199333 \$\endgroup\$ – gbarry Apr 14 '13 at 7:22
3
\$\begingroup\$

There may be tricks regarding the STATUS register but the following generic (untested) code is something I thought of to check the number of bits required to represent each input by doing repeated right bit shift operations until the value is empty.

Then by adding the two results together you should be able to work out if the output will overflow 32 bits.

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);
\$\endgroup\$
2
\$\begingroup\$

Just let the internal result be as wide as the sum of the width of the operands, and then check that the result was not higher than externally allowable. If the PIC18 has a hardware multiplier, this is not really computationally expensive, and is completely accurate, unlike the method of determining the sum of the position of the most significant non-zero digit of the operands.

See pg 174 of the document in http://ptgmedia.pearsoncmg.com/images/0321335724/samplechapter/seacord_ch05.pdf

\$\endgroup\$
  • \$\begingroup\$ PIC18 has an 8 bit hardware multiplier, so multiplies on larger numbers are "reasonably" fast. \$\endgroup\$ – gbarry Apr 14 '13 at 6:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy