ARM Technical Support Knowledge Articles

MULTIPLYING TWO INTS GIVES INCORRECT RESULT

Applies to: General Topics

Answer


Information in this article applies to:


QUESTION

I have written the following code:

int a = 16234;
int b = 1025;
long prodl;

prodl = a * b;

/* this stores only 16 least significant bits
   of the result in prodl */


prodl = (long)a *(long)b;

/* this stores the correct 32-bit result but the
   casting should not be needed */

Why is the result incorrect? Why do I need to cast? Every other compiler I have tried produces the correct 32-bit result.

ANSWER

Section 6.2.1.5 - Usual Arithmetic Conversions of the ANSI C standard states:

"Many binary operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions:

First, if either operand has type long double, the other operand is converted to long double.

Otherwise, if either operand has type double, the other operand is converted to double.

Otherwise, if either operand has type float, the other operand is converted to float.

Otherwise, the integral promotions are performed on both operands. Then the following rules are applied:

If either operand has type unsigned long int, the other operand is converted to unsigned long int.

Otherwise, if one operand has type long int and the other has type unsigned int if a long int can represent all values of an unsigned int the operand of unsigned int is converted to long int; if a long int cannot represent all the values of an unsigned int both operands are converted to unsigned long int.

Otherwise, if either operand has type long int, the other operand is converted to long int.

Otherwise, if either operand has type unsigned int, the other operand is converted to unsigned int.

Otherwise, both operands have type int.

The values of floating operands and of the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby."

So, if both operands have type int, then the result also has type int. If either operand is a long int, then the other operand is converted to a long int and the result is a long int. Our compiler is ANSI C compliant so the following examples produces a long result if a and b are ints:

prodl = (long)a * b;
prodl = a *(long)b;
prodl = (long)a * (long)b;

The following line does not yield the expected 32-bit result either. First a and b are multiplied, but according to the ANSI C Standard, the result is an int. The int is then cast to a long and assigned to prodl:

prodl = (long)(a * b);

Note that on some compilers an int is stored using 32 bits, while on other compilers, an int is stored using 16 bits. The Keil compilers store int types using 16 bits. This explains why some compilers do produce a 32-bit value (they support 32-bit int types).

MORE INFORMATION

Refer to the ANSI C Standard (ANSI/ISO 9899-1990), section 6.2.1.5 - Usual Arithmetic Conversions.

Article last edited on: 2005-07-19 10:22:03

Rate this article

[Bad]
|
|
[Good]
Disagree? Move your mouse over the bar and click

Did you find this article helpful? Yes No

How can we improve this article?

Link to this article
Copyright © 2011 ARM Limited. All rights reserved. External (Open), Non-Confidential