Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are
spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the
password reset link.
Entire forum
➜ Electronics
➜ Microprocessors
➜ Integer arithmetic and overflow
Integer arithmetic and overflow
|
Postings by administrators only.
Refresh page
Posted by
| Nick Gammon
Australia (23,121 posts) Bio
Forum Administrator |
Date
| Mon 16 Sep 2013 09:34 PM (UTC) Amended on Tue 23 Jun 2015 11:17 PM (UTC) by Nick Gammon
|
Message
| On the Arduino (Uno) platform, what do you think will be printed here?
void setup ()
{
Serial.begin (115200);
Serial.println ();
Serial.println (30000 + 30000); // twice 30000
Serial.println (60 * 60 * 24); // seconds in a day
Serial.println (50 / 100 * 1000); // half of 1000
} // end of setup
void loop () { }
Did you guess:
Nope!
It prints:
This is because of integer arithmetic. If the compiler can, it treats an numeric literal (like 60) as an int type, which means it has the range -32768 to +32767.
And, arithmetic is done using the type of the largest argument, which means the arithmetic in each case is done as 16-bit arithmetic, and thus it overflows once it reaches 32767.
For example, 30000 + 30000 = 60000 which is 0xEA60 in hex. Unfortunately, 0xEA60 is exactly how -5536 is stored in an int type, which is why it prints -5536.
Meanwhile, 60 * 60 * 24 = 86400 which is 0x15180 in hex. As that doesn't fit in 16 bits, it is truncated to 0x5180 which is 20864 in decimal (as printed).
Finally, in integer arithmetic 50/100 is zero, multiply zero by 1000 and you still get zero, which is why the final result is zero.
So, can we "help" the compiler by telling it the sort of result we want, like this?
void setup ()
{
Serial.begin (115200);
Serial.println ();
long a = 30000 + 30000;
long b = 60 * 60 * 24;
float c = 50 / 100 * 1000;
Serial.println (a);
Serial.println (b);
Serial.println (c);
} // end of setup
void loop () { }
That prints:
So no, that hasn't helped.
Solution
First, you can add a suffix to numeric literals (eg. L for long, or UL for unsigned long), and add a decimal place to floats, like this:
void setup ()
{
Serial.begin (115200);
Serial.println ();
Serial.println (30000L + 30000); // twice 30000
Serial.println (60L * 60 * 24); // seconds in a day
Serial.println (50.0 / 100 * 1000); // half of 1000
} // end of setup
void loop () { }
Now we get:
You only need to help out with the first literal, once the compiler knows we are using longs (or floats) it sticks with them for the expression.*
Or we can "cast" them:
void setup ()
{
Serial.begin (115200);
Serial.println ();
long a = (long) 30000 + 30000;
long b = (long) 60 * 60 * 24;
float c = (float) 50 / 100 * 1000;
Serial.println (a);
Serial.println (b);
Serial.println (c);
} // end of setup
void loop () { }
Results:
Casting is useful for variables, because you can't just add "L" to the end of a variable name.
An alternative syntax is to use a constructor like this:
void setup ()
{
Serial.begin (115200);
Serial.println ();
long a = long (30000) + 30000;
long b = long (60) * 60 * 24;
float c = float (50) / 100 * 1000;
Serial.println (a);
Serial.println (b);
Serial.println (c);
} // end of setup
void loop () { }
(Same results).
* It's actually somewhat more complex than that as this link explains: Understand integer conversion rules
The compiler "promotes" a value in an expression to match another "higher-ranked" type, under certain circumstances. For example, adding an int and a long will result in the int being promoted to a long (regardless of whether it appears first in the expression or not). However if an int is being added to another int, it will not promote them to a long, even though the result may not fit into an int. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).
To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.
10,852 views.
Postings by administrators only.
Refresh page
top