Product of two integers gives unexpected result

Code:

  int aaa = 1400;
  int bbb = 773;
  int prod = aaa * bbb;
  Serial.println(prod)

  // Prints -31912

According to this: int - Arduino Reference
The range of ints is -2,147,483,648 to 2,147,483,647.

1400 * 773 = 1,082,200, well within that range.

Why am I getting this result?

What Arduino do you have ?

On the Arduino Uno (and other ATmega based boards) an int stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767

You are not using an Arduino with 32 bit integers. Uno, nano, etc are only 16 bit integers.. Change to long int and try again.

I see, thanks.

And FYI, C/C++ does not define the size of int.
On the Uno, it it 2 bytes, but on most PCs, it will be 4 bytes.
This is why you will see people use int16_t (signed), uint16_t, int32_t or uint32_t, etc. Less room for ambiguity.

1 Like

I guess that you have the answer so you can mark your topic as solved by clicking the solution button under the most useful reply.

From the refence page that you linked (emphasis added)

You forgot to mention the board that you are using. But you possibly would not know that it's relevant :wink:

Let us first see why you are getting -31912 instead of 1082200? And then we look into the optimum practices that are to be followed (Step-6).

1. Few things to Know:
It is the responsibility of the programmer to know the meanings of data types and then use appropriate data types for the variables.

The programmer must admit that the sign and magnitude of the content of a variable appear after doing some operation on it.

The content of a variable is always saved in memory in bit from.

2. When you multiply aaa*bbb which are 16-bit positive numbers (aaa = 0x0578 = 1400; bbb = 0x0305 = 773), you expect a value of 1082200 in decimal (0x00108358 in hex); but, you have got -31912 in decimal.

3. Because, you have declared the data type of the destination variable (the prod) as 16-bit (int), the compiler has kept only the lower 16-bit of the result (0x8358) into the variable prod.

4. The Serial.print() command has seen that the destination data type is int (it can hold both +v/-ve value) and the MSBit of the incorrect result (0x8358 = 1000 0011 0101 1000) is 1. Accordingly, the incorrect result (0x8358) has been treated in 2's complement form and -31912 is printed (see calculation below to observe how 0x8358 turns into -31912).
-1x215 + 3x162+5x161+8x160
===> -32768 + 768 + 80 + 8
===> - 31912

5. What is the solution?
The solution lies on your judgement. You know that the input numbers are positive 16-bit; so, the multiplication will produce a positive 32-bit result. Therefore, the data type of the destination variable should be declared unsigned long int (to holds only positive value). So, the variable declarations would be:

  int aaa = 1400;
  int bbb = 773;
  unsigned long int prod = aaa * bbb;
  Serial.println(prod, DEC); shows:  4294935384 in decimal; FFFF8358 in hex

We have still incorrect decimal result/number on the Serial Monitor. The value should be 1082200 (0x108358) and NOT 4294935384 (0XFFFF8358). What is the reason?

When we have declared the destination variable as 32-bit, the compiler has copied the sign bit (1 = the MSBit of 0x108358 = 1 0000 0011 0101 1000) of the result onto vacant upper bits of the 32-bit variable prod. Now, the variable prod contains 0xFFFF8358 and the print() command shows: 4294935384.

What is the correction factor to be applied to get correct result?
We have to tell the compiler to treat the result as a positive number and not to copy the sign bits at the vacant upper bits of the variable prod.

And also to tell the compiler to use 32-bit buffer while doing the multiplication process as (by default) the IDE for UNO uses 16-bit buffer. This can be done by doing this casting: (unsigned long) on the result. Now, the variable declarations are:

  int aaa = 1400;
  int bbb = 773;
  unsigned long int prod = (unsigned long) aaa * bbb;
  Serial.println(prod, DEC); shows:  1082200 (expected result)

6. What is the optimum practice we may follow?

Use appropriate data types and processing buffer size for the input/output variables :

  unsigned int aaa = 1400;
  unsigned int bbb = 773;
  unsigned long int prod = (unsigned long) aaa * bbb; //use 32-bit buffer 
  Serial.println(prod, DEC); shows:  1082200 (
2 Likes

... that you obviously didn't read too closely.

Nope :slight_smile:

Can't imagine how humanity survived before those were introduced

Interesting

So true. Kids these days. Why, in my day, every newbie knew the size of every data type on every platform, and they were never confused. :slightly_smiling_face:

Humanity has no relation at all with those - but the civilization?

tru tru

So int32_t would be the same as "long" on a 16 bit board?

So, what is the difference between following two declarations?:

int y;
uint16_t y;

In Arduino UNO, int-type is 16-bit.
In Arduino DUE, int-type is 32-bit.

Now, if we want that an space of 16-bit wide is to be allocated for variable y whether it is UNO or DUE, then we use int16_t for data type.

int32_t is 32-bit wide. in UNO/DUE.
long is also 32-bit wide in UNO/DUE.

1 Like

So hard to pick just one.

I know; I guess that I would give post #2 by @LarryD the tick as he was the first one and the answer was correct.

Does that post explain/describe why OP is getting -31912 instead of 1082200?

Is this new board from Arduino? only know of 8bit and 32bit boards