Illogical Type Changing

Hey..im new about Arduino..I m experienced in C programming..I m gonna give a little example..

long int myResult;

void setup()
{
Serial.begin(9600);
}

void loop()
{
myResult=1400*1000;
Serial.println(myResult);
while(1);

}

In that example..Programe gave me illogical answer.. If i changed types of 1400 and 1000 as "long int" , i would get right answer..But why i have to change the type of these integer? These are not long integer..Of course the result of two short integers's multiplication might be long integer, just as its here..So i only changed the type of result..Do u think that is logical? Whats the reason of this usage? What do u think?

Nothing at all illogical about 16 bit arithmetic.

1400 or 1000 is not 16 bit(or integer)?

Since 1400 and 1000 will both fit easily in a 16-bit int they are assumed to be of type int. Multiplying them together gives you an int result because those are the rules. It doesn't matter if later in the expression the value is stored in a long.

If you use long constants you will get the result you expect:

  myResult=1400000;  // >16-bit so assumed to be a long constant.
  myResult=1400*1000L;  // One of the values being multiplied is long so the result is long
  myResult=1400L*1000;  // Same here
  myResult=1400L*1000L;   // And you can make them both long from the start

If you are using variables they will have an explicit type but casting can solve the problem:

int height = 1400;
int width = 1000;
myResult = (long)height *  (long)width;
myResult = (long)height *  width;
myResult = height *  (long)width;

cooldoubtless:
1400 or 1000 is not 16 bit(or integer)?

Well, 1440 is 10.45 bit and 1000 is 9.96 bit, but they're both integers.
(Hint : their product is 20.4 bit)

Thanks for all good answers...I know how type changes ,sir. But i think i could not explain the issue.. 1400 and 1000 are integers..So they will be keep in 16 bit memory right? So im using here two 16 bit memory with that two integers...But after ALU operation of these two 16 bit integers i ve to keep the result in 32 bit integer...So i use long integer...Everything is logical here right? Why i ve to use long integer for keeping two integers in memory? Just the result is long integer. So only the type changing of the result must be enough for this arithmetic.

This will work:

  myResult=(long) 1400*1000;

As for why, that's just the C rules. It's nothing to do with the Arduino. It is about type-promotion when evaluating expressions. If the whole expression (RHS) consists of 16-bit integers then the result is truncated to 16 bits before it looks at where to put/use the result.

In particular: Gammon Forum : Electronics : Microprocessors : Integer arithmetic and overflow

And:

https://www.securecoding.cert.org/confluence/display/seccode/INT02-C.+Understand+integer+conversion+rules

Thanks for the answer sir. But C programming that I have learned is a little different :slight_smile: I think this causes from IDE. I will give an example of this program in C. Type changing is like i said. If u run this program u will get 1400000 as result.

#include<stdio.h>

int main( void )
{
	short int a;
	short int b;
	long int result;
	a = 1400;
	b = 1000;
	result = a * b;
	printf("%d",result);
    
	return 0;
}

cooldoubtless:
I think this causes from IDE

The IDE doesn't compile code, so I don't see how that's possible.

I'm very confused right now...Doubtlessly hereafter i will use your suggestions for programming. Because im only programming C 7 years. You all are experts for programming. But i'm sure you will understand me. I'm programming C in that way 7 years and i ve not had any problem until now. I really wonder what the problem is...

Well, no I won't on the Arduino:

void setup()
{
  Serial.begin(115200);

  char buf [20];

  short int a;
  short int b;
  long int result;
  a = 1400;
  b = 1000;
  result = a * b;
  sprintf (buf, "%d",result);
  Serial.println (buf);
}

void loop() { }

Output:

23744

You are confusing the issue by posting code for a different processor.

The "int" type on the Arduino is 16 bits. On other processors it can be 32 bits or 64 bits.

See: C data types - Wikipedia

The type int should be the integer type that the target processor is most efficient working with. This allows great flexibility: for example, all types can be 64-bit. However, several different integer width schemes (data models) are popular. This is because the data model defines how different programs communicate, a uniform data model is used within a given operating system application interface.[3]

On the Arduino, int is 16-bit because the target process or more efficient working with that than 32 bit integers.

Your code above is doing something subtle.

If I replace it with this:

#include<stdio.h>

int main( void )
{
        short int a;
        short int b;
        long int result;
        a = 1400;
        b = 1000;
        result = a * b;
        printf ("Sizeof int = %li\n", sizeof (int));
        printf("%li \n",result);
        return 0;
}

Output (on my Ubuntu PC):

Sizeof int = 4
1400000

The important thing here is that the size of an int is 4 (not 2). Reading the rules on the page I linked above:

Integer types smaller than int are promoted when an operation is performed on them.

So on your Windows/Mac/Ubuntu machine variables a and b are promoted to 32-bit ints. Then they are multiplied. The result fits into 32 bits, so it is not truncated.

On the Arduino there is no promotion to 32 bits, so the results are truncated. This is not the IDE's fault. You need to be aware of the size of the data types on your target machine.

cooldoubtless:
I really wonder what the problem is...

The real problem is that you have been shielded from such problems because you have become used to int being 32 bits. You probably therefore have not needed to worry too much about the exact rules of type promotion.

Interestingly, on my 64-bit Ubuntu PC, this code gives (unexpectedly) correct results:

#include<stdio.h>

int main( void )
{
        long a;
        long b;
        long long result;
        a = 1400000000;
        b = 1000000000;
        result = a * b;
        printf("%lli \n", result);
        return 0;
}

Output:

1400000000000000000

The reason however is that "long" on this processor is in fact 64 bits.

        printf ("Sizeof long = %li \n", sizeof (long));
        printf ("Sizeof long long = %li \n", sizeof (long long));

Output:

Sizeof long = 8 
Sizeof long long = 8

So (surprisingly to me) a long is not 32 bits but 64 bits (on this PC, not on the Arduino).

Sir, i am appreciated for your great answer. But i know i use it on Windows. The rank of the integers are different you are right but if this is about that i can not take this illogical answer...Here i have changed the "result" type as short integer. So the answer is illogical.

#include<stdio.h>

int main( void )
{
	short int a;
	short int b;
	short int result;
	a = 1400;
	b = 1000;
	result = a * b;
	printf("%d",result);
    
	return 0;
}

But after i changed the type of "result" (ATTENTION I VE CHANGED ONLY "RESULT" TYPE NOT OTHER VARIABLES) , the answer is getting right. If this C rules used here the answer should be illogical,but its getting right. So it is not the rank issue sir.

Yes, it is (a promotion issue).

a and b are promoted to int in the expression (despite you making them short int). So they are now 32 bits. You multiply them. The result fits into result. So it looks good.

If you worked on this programe and got this illogical answer...I think u would change all variables types as long integer because you did in Arduino example like that. Am i right? So you would do that...

#include<stdio.h>

int main( void )
{
	short int a;
	short int b;
	long int result;
	a = 1400;
	b = 1000;
	result = (long)a * b                   //ATTENTION
	printf("%d",result);

	return 0;
}

Yes I think that is the simplest solution. By putting (long) there you are telling the compiler that you want the expression to be evaluated as a long, and it then promotes everything after that.

@ Nick
+1...
Thank you for a succinct answer for a lot of questions re types and casting

Doc

result = (long)a * b

By putting (long) there you are telling the compiler that you want the expression to be evaluated as a long

Just to be clear, here the entity being cast to long is "a", not the expression "a * b".
The result of the expression is promoted to the larger of the two datatypes.

If you worked on this programe and got this illogical answer.

Just because a result is outside of your experience, it does not make it "illogical".

AWOL:
Just because a result is outside of your experience, it does not make it "illogical".

should be: