Multiplication error? 7 * 10000 = 4464

Hi all, I can not get my head around following problem on an Arduino Nano:

Serial.println( 7 * 1000);

Serial.println( 7 * 100000);

What I don't understand
Serial.println( 7 * 10000);

I tried a solution as follows to correct:
Serial.println( 7 * 10000.0, 0);

I thought maybe the 10000 is a binairy read by arduino but that would be 112 and (7 times 112) != 4464.

I tried by declaring a variable as unsigned long but that didn't work eigther.

What am I missing?

Integer overflow with 16 bit integer math. Try

Serial.println( 7 * 100000UL);

It appears that 16 bit values are being used. Overflow of a 16 bit unsigned would give 4464.

In the 100000 case it wouldn't fit in 16 bits so was probably promoted to long.

What do you get with
Serial.println( 7 * 10000ul); ?

Both 7 and 10000 will fit in an int data type, do the math is done in ints. But 70000 will not fIt in an int so it overflows*. Try 7 * 10000UL; to force the math to be done in unsigned long.

*70000 - 65536 = 4464.

Thanks for the answers.
I tried

unsigned long d;
d = 7 * 10000;
Serial.println( d);

and got the same 4464.

But as you suggested adding the UL solved the problem.

Then why is

Serial.println( 7 * 1000000000);

not a problem/ not overflowing? because it outputs 7000000000

How large will your number ever need to be?
Will it ever need to be negative?
You can use a uint32_t for large positive only integer types, and int32_t for large positive or negative types.
0 - 2^32 - 1 for uint32_t
-2^16 - 2^16-1 of int_32_t

The max is 4 bytes HEX and never negative. Therefor I tried "d" as an unsigned long.
a uint32_t also returns 4464..

This needs to be

Serial.println( 7 x 100000000)

one zero less... sorry type..

The compiler does things in steps. A 10000 is seen as a integer, regardless if you put that in a certain variable. A 7 is a integer. So the compiler sees two integers and does therefor a integer multiplication. Then the compiler can put the result into a unsigned long.

A 1000000000 does not fit into a normal 16-bit int, but luckily it still fits in a unsigned long. The compiler tries to help you and does not use integers anymore. But the default for a compiler is always int on every Arduino board, on every platform.

Sometimes when using 8-bit bytes, the compiler chooses int for a calculation. There are very clear rules for that, but even I don't know all those language and compiler rules.

You can avoid all problems by always using 'UL' for numbers and always use unsigned long variables.
Then you are sure that the compiler understands what you want, and it is helpful for yourself as well, because it clearly shows that the code is with unsigned long:

// unsigned long ? then unsigned long everywhere.
unsigned long a = 1UL;
unsigned long b = a + 2UL;
unsigned long d = 7UL * 10000UL;
Serial.println( 7UL * 10000UL);

// float ? then float everywhere:
float p = 1.0;
float q = p * 3.456789;
float r = (float) analogRead(A0);     // cast to float

The Arduino reference shows the limits for 32-bit unsigned long:

1 Like

Should read "The compiler tries to help you and does not use ints anymore."

char, int and long (and variants thereof) are all integer types

1 Like

In decimal arithmetic 7 * 10000 = 70000

In binary arithmetic this is 0001 0001 0001 0111 0000 (hex 0x11170).

Most likely, as mentioned above, the result is truncated to 16 bits. This means that only the first 16 bits (counting from the right) will fit in the result. Truncation occurs before the result is stored in a variable, and by then it does not matter if this variable is 32 bits wide, because the result has been truncated.

The result here would then be truncated to 16 bits and is 0001 0001 0111 0000, which is 4464 in decimal (hex 0x1170).

To force the arithmetic to be performed using long integers (before it is ever stored in a variable), at least one of the operands must be a long integer. You can achieve this forcing 70000 as in 70000L, or using a long variable in the multiplication.

The data type of the number to the left of the = does not matter. The numbers to the right of the = will still both fit in an int data type so the math is done with ints. The result is too big to fit into an int so it is truncated and put into the variable on the left even though the variable on the left is an unsigned long data type.

1 Like

Thanks all, this helps a lot and I have learned something new. Now I understand why I ran into this problem. Thanks again.

This ↑ should be in an FAQ (if it isn't already), as should this ↓ .

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.