Simple multiplication bug












5















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);

}









share|improve this question




















  • 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 be 0 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
















5















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);

}









share|improve this question




















  • 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 be 0 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














5












5








5








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);

}









share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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





    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





    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 be 0 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










2 Answers
2






active

oldest

votes


















11














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".






share|improve this answer


























  • @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



















0














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.






share|improve this answer


























  • 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











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
});


}
});














draft saved

draft discarded


















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









11














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".






share|improve this answer


























  • @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
















11














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".






share|improve this answer


























  • @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














11












11








11







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".






share|improve this answer















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".







share|improve this answer














share|improve this answer



share|improve this answer








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 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



















  • @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

















@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











0














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.






share|improve this answer


























  • 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
















0














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.






share|improve this answer


























  • 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














0












0








0







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.






share|improve this answer















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.







share|improve this answer














share|improve this answer



share|improve this answer








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



















  • 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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

ComboBox Display Member on multiple fields

Is it possible to collect Nectar points via Trainline?