Pages: [1] 2   Go Down
Author Topic: Addition overflow  (Read 1782 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 2
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I have a doubt whit the addition instruction and know if an overflow happened.

uint8_t a = 200;
uint8_t b = 200;

uint8_t c = a + b; // the sum is overflowed

// c is 200 + 200 = 400 >>> 400 - 255 = 145

I can tell if the sum is overflowed.

In ASM normally I have the carry bit to know that. In C and in Arduino, can I use a instruction, flag or something similar?

Thanks.
« Last Edit: October 29, 2012, 10:53:32 pm by leonelpepe » Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In C and in Arduino, can I use a instruction, flag or something similar?

No, there's nothing like that.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 2
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, it is a very bad news. The only way that I can tinks is that c must be greather than a and b at the same time:

Code:

uint8_t a = 200;
uint8_t b = 200;

uint8_t c = a + b; // the sum is overloaded

// c is 200 + 200 = 400 >>> 400 - 255 = 145

if (c < a && c < b) {
  // Overload have being success.
}
Logged

Des Moines, WA - USA
Offline Offline
God Member
*****
Karma: 25
Posts: 779
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think you're referring to 'overflow' not overload.
Logged

Offline Offline
Newbie
*
Karma: 2
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think you're referring to 'overflow' not overload.


mmm. Yes, I'm not speak English very well. Sorry.
Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 212
Posts: 13085
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Give this a try...

Code:
bool SafeAdd( uint8_t a, uint8_t b, uint8_t & r )
{
  uint16_t t;
 
  t = a + b;
 
  r = t;
 
  return( (t & 0xFF00) == 0 );
}

bool SafeAdd( uint16_t a, uint16_t b, uint16_t & r )
{
  uint32_t t;
 
  t = a + b;
 
  r = t;
 
  return( (t & 0xFFFF0000) == 0 );
}

void Test1( void )
{
  uint8_t a = 200;
  uint8_t b = 200;
  uint8_t r;

  if ( SafeAdd( a, b, r ) )
  {
    Serial.println( F( "No problem." ) );
  }
  else
  {
    Serial.println( F( "Bad news!" ) );
  }
}

void Test2( void )
{
  uint8_t a = 200;
  uint16_t b = 200;
  uint16_t r;

  if ( SafeAdd( a, b, r ) )
  {
    Serial.println( F( "No problem." ) );
  }
  else
  {
    Serial.println( F( "Bad news!" ) );
  }
}

void setup( void )
{
  Serial.begin( 250000 );
 
  Test1();
  Test2();
}

void loop( void )
{
}
Logged

Offline Offline
Newbie
*
Karma: 2
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Give this a try...


It is a great idea. Thanks, but... if I want to use a 32 bit variable? jaja
Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 212
Posts: 13085
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Then you use uint64_t for the result.
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think, but am not sure, you can access the microcontroller "status register" from C code.

I think in "Arduino C" there is a special variable called "SREG" which is a representation of the status register of the microcontroller. The microcontroller status register contains a collection of flags and one of those flags is the carry flag. I think the carry flag is the flag in the status register bit0 .

You could try something like this:

Code:
boolean isCarryOverflow()
{
return(SREG & 0x01); //Assuming the carry flag in on bit0
}

void setup()
{
...
...
c = a + b;
if(isCarryOverflow)
{
...
}
...
}

ATmega datasheet >> http://www.atmel.com/Images/doc8161.pdf (page 10)
http://www.wvshare.com/article/AVR-1-1-5.htm

You can download the datasheet of your Arduino microcontroller from arduino.cc >> Products
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 76
Posts: 2247
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
• Bit 0 – C: Carry Flag
The Carry Flag C indicates a carry in an arithmetic or logic operation. See the “Instruction Set
Description” for detailed information.

Yeah its bit 0, there is also an instruction 'BSET' for checking bits in the status register.
Logged


Worst state in America
Offline Offline
God Member
*****
Karma: 32
Posts: 819
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I have a doubt whit the addition instruction and know if an overflow happened.

uint8_t a = 200;
uint8_t b = 200;

uint8_t c = a + b; // the sum is overflowed

An unsigned 8 bit INT can only hold a value from 0 to 255 (decimal). If you add one to 255, it "rolls over" back to zero.

You need to use a larger INT... maybe a uint16_t (16 bits - 0 to 65535) or a uint32_t (32 bits - 0 to 4294967295) or even a uint64_t (64 bits.... ginormous!)

You can detect if a variable has overflowed. There is no carry bit available to C, but if the result is smaller than you expect, you can assume that an overflow has occurred.

Note that this is also true with subtraction... a uint8_t with a value of 0, minus 1 = 255. In this case, the result is larger than you expect and this signifies a borrow.
Logged

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 212
Posts: 13085
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think, but am not sure, you can access the microcontroller "status register" from C code.

You can but doing so is "dangerous".  The compiler can reorder (or even remove) code when it optimizes.  When you write this...

Quote
c = a + b;
if(isCarryOverflow())
{
...
}
// Some code after the if that has no dependency on anything above.


The compiler could do something like this...

Quote
c = a + b;
// Some code that was after the if that has no dependency on anything nearby.
if(isCarryOverflow())
{
...
}

In other words, there is no way to guarantee the SREG check is performed immediately after the addition.
« Last Edit: November 07, 2012, 01:10:14 pm by Coding Badly » Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can but doing so is "dangerous".  The compiler can reorder (or even remove) code when it optimizes.  When you write this...

Yes, the compiler optimizer is always surprising.

This guy (http://www.fefe.de/intof.html) says that if an addtion  of integers owerflowed, then the sum is always less than either addend. (I do not know the reason)

Then, say, we have A which is an integer of 48 bits, consisting A_Hi (16 bits) and A_Low (32 bits) and we add B which is a 32-bit integer.

Maybe something like that would work

Code:
unsigned int A_Hi;
unsigned long A_Low;
unsigned long B;

A_Low += B;
if(B > A_Low) A_Hi ++;

(I apologize for my horrid English)
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This guy (http://www.fefe.de/intof.html) says that if an addtion  of integers owerflowed, then the sum is always less than either addend. (I do not know the reason)

I haven't followed that link, but I expect you meant to say that at least one of the addends will be greater than the sum (they may not both be greater).
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 227
Posts: 14048
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I haven't followed that link, but I expect you meant to say that at least one of the addends will be greater than the sum (they may not both be greater).

if a <=255 and b<=255 and a+b > 255 ==>  (a+b)%256 < a  and (a+b)%256 < b

you can test this quite simple
Code:
void setup()
{
  Serial.begin(115200);
  for (uint8_t a = 0; a < 255; a++) // 255 not in the loop to prevent endless loop
    for (uint8_t b = 0; b < 255; b++)
    {
      uint8_t c = a + b;
      uint16_t d = (uint16_t )a + b;
      Serial.print((int)a);
      Serial.print('\t');
      Serial.print((int)b);
      Serial.print('\t');
      Serial.print((int)c);
      Serial.print('\t');
      Serial.print(c < a?"overflow":"ok");
      Serial.println();
    }
}
void loop(){}

but you can test overflow before it occurs just by doing a subtraction, no need to test a register, works for 16, 32 and 64 bit

Code:
void setup()
{
  Serial.begin(115200);
  for (uint8_t a = 0; a < 255; a++)
    for (uint8_t b = 0; b < 255; b++)
    {
      if (255 - b < a ) Serial.println("overflow");
      else Serial.println((int)(a+b));
    }
}
void loop(){}


Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: [1] 2   Go Up
Jump to: