Simple multiplication bug
Executing the following code always gives -511 as a result, I performed many tests, and it seems that results are correct from 0 * 0 to 181 * 181, beyond that, results are abnormal, I tried many types for the z variable (int, long, float) without success, any idea? I'm using the Arduino Uno.
long z = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
z = 255 * 255;
Serial.println(z);
delay(200);
}
arduino-uno
add a comment |
Executing the following code always gives -511 as a result, I performed many tests, and it seems that results are correct from 0 * 0 to 181 * 181, beyond that, results are abnormal, I tried many types for the z variable (int, long, float) without success, any idea? I'm using the Arduino Uno.
long z = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
z = 255 * 255;
Serial.println(z);
delay(200);
}
arduino-uno
2
Hint: Try "z = 255 * 255L;" or "z = 255 * (long) 255;"
– Mikael Patel
Feb 5 at 10:25
I did. @MikaelPatel I worked indeed, could you explain the reason behind this, and is there similar cases for other types?
– Huskarnov
Feb 5 at 10:32
4
This "bug" is as old as programming. When you write "255" compiler creates an "integer constant" with value of 255. When you multiply 255 by 255 you multiply two "integer constants" and by convention result of such multiplication is an "integer". Then you implicitly cast it to long when doing assignment. When you multiply "255" by "255L" you actually multiply "integer constant" by "long constant" and result of such multiplication is "long". You will see similar issue when you writefloat z = 1 / 5
result will be0
because integer division results with integer that is later casted to float.
– Filip Franik
Feb 5 at 10:54
3
Ref: gcc.gnu.org/wiki/avr-gcc is all the information you need for the AVR GCC compiler. It all has to do with 1) number range of "int" for a given target, and 2) compiler evaluation of constant expressions.
– Mikael Patel
Feb 5 at 11:03
@MikaelPatel You should answer the questions instead of writing snippets of them in the comment section.
– pipe
Feb 5 at 12:57
add a comment |
Executing the following code always gives -511 as a result, I performed many tests, and it seems that results are correct from 0 * 0 to 181 * 181, beyond that, results are abnormal, I tried many types for the z variable (int, long, float) without success, any idea? I'm using the Arduino Uno.
long z = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
z = 255 * 255;
Serial.println(z);
delay(200);
}
arduino-uno
Executing the following code always gives -511 as a result, I performed many tests, and it seems that results are correct from 0 * 0 to 181 * 181, beyond that, results are abnormal, I tried many types for the z variable (int, long, float) without success, any idea? I'm using the Arduino Uno.
long z = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
z = 255 * 255;
Serial.println(z);
delay(200);
}
arduino-uno
arduino-uno
edited Feb 5 at 9:49
Michel Keijzers
6,64441738
6,64441738
asked Feb 5 at 9:36
HuskarnovHuskarnov
293
293
2
Hint: Try "z = 255 * 255L;" or "z = 255 * (long) 255;"
– Mikael Patel
Feb 5 at 10:25
I did. @MikaelPatel I worked indeed, could you explain the reason behind this, and is there similar cases for other types?
– Huskarnov
Feb 5 at 10:32
4
This "bug" is as old as programming. When you write "255" compiler creates an "integer constant" with value of 255. When you multiply 255 by 255 you multiply two "integer constants" and by convention result of such multiplication is an "integer". Then you implicitly cast it to long when doing assignment. When you multiply "255" by "255L" you actually multiply "integer constant" by "long constant" and result of such multiplication is "long". You will see similar issue when you writefloat z = 1 / 5
result will be0
because integer division results with integer that is later casted to float.
– Filip Franik
Feb 5 at 10:54
3
Ref: gcc.gnu.org/wiki/avr-gcc is all the information you need for the AVR GCC compiler. It all has to do with 1) number range of "int" for a given target, and 2) compiler evaluation of constant expressions.
– Mikael Patel
Feb 5 at 11:03
@MikaelPatel You should answer the questions instead of writing snippets of them in the comment section.
– pipe
Feb 5 at 12:57
add a comment |
2
Hint: Try "z = 255 * 255L;" or "z = 255 * (long) 255;"
– Mikael Patel
Feb 5 at 10:25
I did. @MikaelPatel I worked indeed, could you explain the reason behind this, and is there similar cases for other types?
– Huskarnov
Feb 5 at 10:32
4
This "bug" is as old as programming. When you write "255" compiler creates an "integer constant" with value of 255. When you multiply 255 by 255 you multiply two "integer constants" and by convention result of such multiplication is an "integer". Then you implicitly cast it to long when doing assignment. When you multiply "255" by "255L" you actually multiply "integer constant" by "long constant" and result of such multiplication is "long". You will see similar issue when you writefloat z = 1 / 5
result will be0
because integer division results with integer that is later casted to float.
– Filip Franik
Feb 5 at 10:54
3
Ref: gcc.gnu.org/wiki/avr-gcc is all the information you need for the AVR GCC compiler. It all has to do with 1) number range of "int" for a given target, and 2) compiler evaluation of constant expressions.
– Mikael Patel
Feb 5 at 11:03
@MikaelPatel You should answer the questions instead of writing snippets of them in the comment section.
– pipe
Feb 5 at 12:57
2
2
Hint: Try "z = 255 * 255L;" or "z = 255 * (long) 255;"
– Mikael Patel
Feb 5 at 10:25
Hint: Try "z = 255 * 255L;" or "z = 255 * (long) 255;"
– Mikael Patel
Feb 5 at 10:25
I did. @MikaelPatel I worked indeed, could you explain the reason behind this, and is there similar cases for other types?
– Huskarnov
Feb 5 at 10:32
I did. @MikaelPatel I worked indeed, could you explain the reason behind this, and is there similar cases for other types?
– Huskarnov
Feb 5 at 10:32
4
4
This "bug" is as old as programming. When you write "255" compiler creates an "integer constant" with value of 255. When you multiply 255 by 255 you multiply two "integer constants" and by convention result of such multiplication is an "integer". Then you implicitly cast it to long when doing assignment. When you multiply "255" by "255L" you actually multiply "integer constant" by "long constant" and result of such multiplication is "long". You will see similar issue when you write
float z = 1 / 5
result will be 0
because integer division results with integer that is later casted to float.– Filip Franik
Feb 5 at 10:54
This "bug" is as old as programming. When you write "255" compiler creates an "integer constant" with value of 255. When you multiply 255 by 255 you multiply two "integer constants" and by convention result of such multiplication is an "integer". Then you implicitly cast it to long when doing assignment. When you multiply "255" by "255L" you actually multiply "integer constant" by "long constant" and result of such multiplication is "long". You will see similar issue when you write
float z = 1 / 5
result will be 0
because integer division results with integer that is later casted to float.– Filip Franik
Feb 5 at 10:54
3
3
Ref: gcc.gnu.org/wiki/avr-gcc is all the information you need for the AVR GCC compiler. It all has to do with 1) number range of "int" for a given target, and 2) compiler evaluation of constant expressions.
– Mikael Patel
Feb 5 at 11:03
Ref: gcc.gnu.org/wiki/avr-gcc is all the information you need for the AVR GCC compiler. It all has to do with 1) number range of "int" for a given target, and 2) compiler evaluation of constant expressions.
– Mikael Patel
Feb 5 at 11:03
@MikaelPatel You should answer the questions instead of writing snippets of them in the comment section.
– pipe
Feb 5 at 12:57
@MikaelPatel You should answer the questions instead of writing snippets of them in the comment section.
– pipe
Feb 5 at 12:57
add a comment |
2 Answers
2
active
oldest
votes
No, this is not a bug. You are using a compile time constant expression which is signed int
unless told otherwise. Therefore you can only represent numbers between -32768 and 32767. Your computation of 255 * 255 = 65025
exceeds the range. Thus you see an overflow. In the C/C++ standard the overflow of signed types is actually undefined behavior. That means that the compiler is allowed to do anything from showing the correct answer to halt and catch fire. Only unsigned types with a known size like uint16_t
have a well-defined overflow behaviour. You should promote your right hand side computation to unsigned type like this:
z = 255U * 255U;
This way you tell the compiler your intention and don't land in "Undefined-Behaviour-Land".
@Juraj Right, I thought it was signed 16 bit just asint
. But the latter is still true. Compile time constants aresigned int
, which is 16 bit. So the right side of the assignement is the problem.
– Kwasmich
Feb 5 at 10:39
wrap around
doesn't sound right - but I know what you're saying
– Jaromanda X
Feb 5 at 11:37
add a comment |
Assuming long is 4 bytes, it should work.
However, if somehow a long type is only 2 bytes, or (more likely) you used another type or there is some wrong define/typedef, and it is a signed long (default if you do not used the unsigned keyword), the value range is -32,768 to 32,767 and 255 * 255 = 65,025 which is out of range.
So you can first try to use unsigned long
.
long is -2,147,483,648 to 2,147,483,647
– Juraj
Feb 5 at 10:30
With unsigned long the result becomes :4294966785.
– Huskarnov
Feb 5 at 10:40
Kwasmich's answer is correct
– Juraj
Feb 5 at 10:44
@Juraj - one short there :p
– Jaromanda X
Feb 5 at 11:36
2
it is not. Kwasmich explains
– Juraj
Feb 5 at 13:42
|
show 1 more comment
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("schematics", function () {
StackExchange.schematics.init();
});
}, "cicuitlab");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "540"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2farduino.stackexchange.com%2fquestions%2f61276%2fsimple-multiplication-bug%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
No, this is not a bug. You are using a compile time constant expression which is signed int
unless told otherwise. Therefore you can only represent numbers between -32768 and 32767. Your computation of 255 * 255 = 65025
exceeds the range. Thus you see an overflow. In the C/C++ standard the overflow of signed types is actually undefined behavior. That means that the compiler is allowed to do anything from showing the correct answer to halt and catch fire. Only unsigned types with a known size like uint16_t
have a well-defined overflow behaviour. You should promote your right hand side computation to unsigned type like this:
z = 255U * 255U;
This way you tell the compiler your intention and don't land in "Undefined-Behaviour-Land".
@Juraj Right, I thought it was signed 16 bit just asint
. But the latter is still true. Compile time constants aresigned int
, which is 16 bit. So the right side of the assignement is the problem.
– Kwasmich
Feb 5 at 10:39
wrap around
doesn't sound right - but I know what you're saying
– Jaromanda X
Feb 5 at 11:37
add a comment |
No, this is not a bug. You are using a compile time constant expression which is signed int
unless told otherwise. Therefore you can only represent numbers between -32768 and 32767. Your computation of 255 * 255 = 65025
exceeds the range. Thus you see an overflow. In the C/C++ standard the overflow of signed types is actually undefined behavior. That means that the compiler is allowed to do anything from showing the correct answer to halt and catch fire. Only unsigned types with a known size like uint16_t
have a well-defined overflow behaviour. You should promote your right hand side computation to unsigned type like this:
z = 255U * 255U;
This way you tell the compiler your intention and don't land in "Undefined-Behaviour-Land".
@Juraj Right, I thought it was signed 16 bit just asint
. But the latter is still true. Compile time constants aresigned int
, which is 16 bit. So the right side of the assignement is the problem.
– Kwasmich
Feb 5 at 10:39
wrap around
doesn't sound right - but I know what you're saying
– Jaromanda X
Feb 5 at 11:37
add a comment |
No, this is not a bug. You are using a compile time constant expression which is signed int
unless told otherwise. Therefore you can only represent numbers between -32768 and 32767. Your computation of 255 * 255 = 65025
exceeds the range. Thus you see an overflow. In the C/C++ standard the overflow of signed types is actually undefined behavior. That means that the compiler is allowed to do anything from showing the correct answer to halt and catch fire. Only unsigned types with a known size like uint16_t
have a well-defined overflow behaviour. You should promote your right hand side computation to unsigned type like this:
z = 255U * 255U;
This way you tell the compiler your intention and don't land in "Undefined-Behaviour-Land".
No, this is not a bug. You are using a compile time constant expression which is signed int
unless told otherwise. Therefore you can only represent numbers between -32768 and 32767. Your computation of 255 * 255 = 65025
exceeds the range. Thus you see an overflow. In the C/C++ standard the overflow of signed types is actually undefined behavior. That means that the compiler is allowed to do anything from showing the correct answer to halt and catch fire. Only unsigned types with a known size like uint16_t
have a well-defined overflow behaviour. You should promote your right hand side computation to unsigned type like this:
z = 255U * 255U;
This way you tell the compiler your intention and don't land in "Undefined-Behaviour-Land".
edited Feb 8 at 7:19
linhartr22
44639
44639
answered Feb 5 at 9:51
KwasmichKwasmich
847414
847414
@Juraj Right, I thought it was signed 16 bit just asint
. But the latter is still true. Compile time constants aresigned int
, which is 16 bit. So the right side of the assignement is the problem.
– Kwasmich
Feb 5 at 10:39
wrap around
doesn't sound right - but I know what you're saying
– Jaromanda X
Feb 5 at 11:37
add a comment |
@Juraj Right, I thought it was signed 16 bit just asint
. But the latter is still true. Compile time constants aresigned int
, which is 16 bit. So the right side of the assignement is the problem.
– Kwasmich
Feb 5 at 10:39
wrap around
doesn't sound right - but I know what you're saying
– Jaromanda X
Feb 5 at 11:37
@Juraj Right, I thought it was signed 16 bit just as
int
. But the latter is still true. Compile time constants are signed int
, which is 16 bit. So the right side of the assignement is the problem.– Kwasmich
Feb 5 at 10:39
@Juraj Right, I thought it was signed 16 bit just as
int
. But the latter is still true. Compile time constants are signed int
, which is 16 bit. So the right side of the assignement is the problem.– Kwasmich
Feb 5 at 10:39
wrap around
doesn't sound right - but I know what you're saying– Jaromanda X
Feb 5 at 11:37
wrap around
doesn't sound right - but I know what you're saying– Jaromanda X
Feb 5 at 11:37
add a comment |
Assuming long is 4 bytes, it should work.
However, if somehow a long type is only 2 bytes, or (more likely) you used another type or there is some wrong define/typedef, and it is a signed long (default if you do not used the unsigned keyword), the value range is -32,768 to 32,767 and 255 * 255 = 65,025 which is out of range.
So you can first try to use unsigned long
.
long is -2,147,483,648 to 2,147,483,647
– Juraj
Feb 5 at 10:30
With unsigned long the result becomes :4294966785.
– Huskarnov
Feb 5 at 10:40
Kwasmich's answer is correct
– Juraj
Feb 5 at 10:44
@Juraj - one short there :p
– Jaromanda X
Feb 5 at 11:36
2
it is not. Kwasmich explains
– Juraj
Feb 5 at 13:42
|
show 1 more comment
Assuming long is 4 bytes, it should work.
However, if somehow a long type is only 2 bytes, or (more likely) you used another type or there is some wrong define/typedef, and it is a signed long (default if you do not used the unsigned keyword), the value range is -32,768 to 32,767 and 255 * 255 = 65,025 which is out of range.
So you can first try to use unsigned long
.
long is -2,147,483,648 to 2,147,483,647
– Juraj
Feb 5 at 10:30
With unsigned long the result becomes :4294966785.
– Huskarnov
Feb 5 at 10:40
Kwasmich's answer is correct
– Juraj
Feb 5 at 10:44
@Juraj - one short there :p
– Jaromanda X
Feb 5 at 11:36
2
it is not. Kwasmich explains
– Juraj
Feb 5 at 13:42
|
show 1 more comment
Assuming long is 4 bytes, it should work.
However, if somehow a long type is only 2 bytes, or (more likely) you used another type or there is some wrong define/typedef, and it is a signed long (default if you do not used the unsigned keyword), the value range is -32,768 to 32,767 and 255 * 255 = 65,025 which is out of range.
So you can first try to use unsigned long
.
Assuming long is 4 bytes, it should work.
However, if somehow a long type is only 2 bytes, or (more likely) you used another type or there is some wrong define/typedef, and it is a signed long (default if you do not used the unsigned keyword), the value range is -32,768 to 32,767 and 255 * 255 = 65,025 which is out of range.
So you can first try to use unsigned long
.
edited Feb 5 at 12:07
Juraj
7,5052927
7,5052927
answered Feb 5 at 9:51
Michel KeijzersMichel Keijzers
6,64441738
6,64441738
long is -2,147,483,648 to 2,147,483,647
– Juraj
Feb 5 at 10:30
With unsigned long the result becomes :4294966785.
– Huskarnov
Feb 5 at 10:40
Kwasmich's answer is correct
– Juraj
Feb 5 at 10:44
@Juraj - one short there :p
– Jaromanda X
Feb 5 at 11:36
2
it is not. Kwasmich explains
– Juraj
Feb 5 at 13:42
|
show 1 more comment
long is -2,147,483,648 to 2,147,483,647
– Juraj
Feb 5 at 10:30
With unsigned long the result becomes :4294966785.
– Huskarnov
Feb 5 at 10:40
Kwasmich's answer is correct
– Juraj
Feb 5 at 10:44
@Juraj - one short there :p
– Jaromanda X
Feb 5 at 11:36
2
it is not. Kwasmich explains
– Juraj
Feb 5 at 13:42
long is -2,147,483,648 to 2,147,483,647
– Juraj
Feb 5 at 10:30
long is -2,147,483,648 to 2,147,483,647
– Juraj
Feb 5 at 10:30
With unsigned long the result becomes :4294966785.
– Huskarnov
Feb 5 at 10:40
With unsigned long the result becomes :4294966785.
– Huskarnov
Feb 5 at 10:40
Kwasmich's answer is correct
– Juraj
Feb 5 at 10:44
Kwasmich's answer is correct
– Juraj
Feb 5 at 10:44
@Juraj - one short there :p
– Jaromanda X
Feb 5 at 11:36
@Juraj - one short there :p
– Jaromanda X
Feb 5 at 11:36
2
2
it is not. Kwasmich explains
– Juraj
Feb 5 at 13:42
it is not. Kwasmich explains
– Juraj
Feb 5 at 13:42
|
show 1 more comment
Thanks for contributing an answer to Arduino Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2farduino.stackexchange.com%2fquestions%2f61276%2fsimple-multiplication-bug%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Hint: Try "z = 255 * 255L;" or "z = 255 * (long) 255;"
– Mikael Patel
Feb 5 at 10:25
I did. @MikaelPatel I worked indeed, could you explain the reason behind this, and is there similar cases for other types?
– Huskarnov
Feb 5 at 10:32
4
This "bug" is as old as programming. When you write "255" compiler creates an "integer constant" with value of 255. When you multiply 255 by 255 you multiply two "integer constants" and by convention result of such multiplication is an "integer". Then you implicitly cast it to long when doing assignment. When you multiply "255" by "255L" you actually multiply "integer constant" by "long constant" and result of such multiplication is "long". You will see similar issue when you write
float z = 1 / 5
result will be0
because integer division results with integer that is later casted to float.– Filip Franik
Feb 5 at 10:54
3
Ref: gcc.gnu.org/wiki/avr-gcc is all the information you need for the AVR GCC compiler. It all has to do with 1) number range of "int" for a given target, and 2) compiler evaluation of constant expressions.
– Mikael Patel
Feb 5 at 11:03
@MikaelPatel You should answer the questions instead of writing snippets of them in the comment section.
– pipe
Feb 5 at 12:57