215

I want to be better about knowing when I should cast. What are the implicit type conversion rules in C++ when adding, multiplying, etc. For example,

int + float = ?
int * float = ?
float * int = ?
int / float = ?
float / int = ?
int / int = ?
int ^ float = ?

et cetera...

Will the expression always be evaluated as the more precise type? Do the rules differ for Java? Please correct me if I have worded this question inaccurately.

2
  • 20
    Keep in mind ^ is XOR.
    – GManNickG
    Apr 6, 2011 at 7:59
  • 19
    @int ^ float = compile error :) Apr 6, 2011 at 8:37

9 Answers 9

280

In C++ operators (for POD types) always act on objects of the same type.
Thus if they are not the same one will be promoted to match the other.
The type of the result of the operation is the same as operands (after conversion).

if:
either is      long double       other is promoted >      long double
either is           double       other is promoted >           double
either is           float        other is promoted >           float
either is long long unsigned int other is promoted > long long unsigned int
either is long long          int other is promoted > long long          int
either is long      unsigned int other is promoted > long      unsigned int
either is long               int other is promoted > long               int
either is           unsigned int other is promoted >           unsigned int
either is                    int other is promoted >                    int

Otherwise:
both operands are promoted to int

Note. The minimum size of operations is int. So short/char are promoted to int before the operation is done.

In all your expressions the int is promoted to a float before the operation is performed. The result of the operation is a float.

int + float =>  float + float = float
int * float =>  float * float = float
float * int =>  float * float = float
int / float =>  float / float = float
float / int =>  float / float = float
int / int                     = int
int ^ float =>  <compiler error>
23
  • 1
    "The minimum size of operations is int." - This would be very strange (what about architectures that efficiently support char/short operations?) Is this really in the C++ spec? Apr 6, 2011 at 7:59
  • 5
    @Rafal: Yes. int is supposed to be the most efficient integer type for operation on a particular platform. char must always be 1 but short can be the same size as int. Apr 6, 2011 at 8:08
  • 2
    @Rafał: yes, it is very strange and it is is in the standard. In a lot of cases, the architecture you describe could use its super-efficient char type. If the value of char + char is assigned to a char, then it can just do the arithmetic in char and for example wrap around. But if the result is assigned to int then it has to do the arithmetic in a type large enough to get the correct result when it's more than CHAR_MAX. Apr 6, 2011 at 8:27
  • 8
    I just want to emphasize the fact that int gets promoted to unsigned int!!! I've struggled with bugs for days because I was under the impression that both would be promoted to int or long so that a possible negative result would not cause an underflow/wrap-around.
    – nitsas
    Apr 24, 2013 at 12:53
  • 15
    Example of the problem "int gets promoted to unsigned int": ((int) 4) - ((unsigned int) 5) will result in 4294967295 for 32 bit ints and 32 bit unsigned ints.
    – nitsas
    Apr 24, 2013 at 13:15
41

Arithmetic operations involving float results in float.

int + float = float
int * float = float
float * int = float
int / float = float
float / int = float
int / int = int

For more detail answer. Look at what the section §5/9 from the C++ Standard says

Many binary operators that expect operands of arithmetic or enumeration 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, which are defined as follows:

— If either operand is of type long double, the other shall be converted to long double.

— Otherwise, if either operand is double, the other shall be converted to double.

— Otherwise, if either operand is float, the other shall be converted to float.

— Otherwise, the integral promotions (4.5) shall be performed on both operands.54)

— Then, if either operand is unsigned long the other shall be converted to unsigned long.

— Otherwise, if one operand is a long int and the other unsigned int, then if a long int can represent all the values of an unsigned int, the unsigned int shall be converted to a long int; otherwise both operands shall be converted to unsigned long int.

— Otherwise, if either operand is long, the other shall be converted to long.

— Otherwise, if either operand is unsigned, the other shall be converted to unsigned.

[Note: otherwise, the only remaining case is that both operands are int ]

5
  • 4
    ...so long as the other type is neither double nor long double.
    – CB Bailey
    Apr 6, 2011 at 7:53
  • 1
    @Charles: Correct. I quoted the relevant section from the Standard to clarify further. Apr 6, 2011 at 7:58
  • So can an integer always be converted to float without any data loss? (e.g. by zero-ing the exponent and using everything for the mantissa) ?
    – Marco A.
    Feb 25, 2014 at 13:25
  • 1
    This answer is out-of-date. Suggest update. In particular, long long and unsigned long not addressed right here. Jan 7, 2016 at 18:39
  • @MarcoA. a 32-bit float doesn't have enough bits in the mantissa (24 bits for IEEE-754) for a 32-bit int, so there might be some data loss. A 64-bit double should be just fine. Jun 2, 2020 at 13:55
20

Since the other answers don't talk about the rules in C++11 here's one. From C++11 standard (draft n3337) §5/9 (emphasized the difference):

This pattern is called the usual arithmetic conversions, which are defined as follows:

— If either operand is of scoped enumeration type, no conversions are performed; if the other operand does not have the same type, the expression is ill-formed.

— If either operand is of type long double, the other shall be converted to long double.

— Otherwise, if either operand is double, the other shall be converted to double.

— Otherwise, if either operand is float, the other shall be converted to float.

— Otherwise, the integral promotions shall be performed on both operands. Then the following rules shall be applied to the promoted operands:

— If both operands have the same type, no further conversion is needed.

— Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank shall be converted to the type of the operand with greater rank.

— Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type.

— Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type.

— Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

See here for a list that's frequently updated.

1
  • 2
    These rules were the same in all versions of C++, except for scoped enumerations which were added in C++11 of course
    – M.M
    Sep 4, 2019 at 22:43
8

This answer is directed in large part at a comment made by @RafałDowgird:

"The minimum size of operations is int." - This would be very strange (what about architectures that efficiently support char/short operations?) Is this really in the C++ spec?

Keep in mind that the C++ standard has the all-important "as-if" rule. See section 1.8: Program Execution:

3) This provision is sometimes called the "as-if" rule, because an implementation is free to disregard any requirement of the Standard as long as the result is as if the requirement had been obeyed, as far as can be determined from the observable behavior of the program.

The compiler cannot set an int to be 8 bits in size, even if it were the fastest, since the standard mandates a 16-bit minimum int.

Therefore, in the case of a theoretical computer with super-fast 8-bit operations, the implicit promotion to int for arithmetic could matter. However, for many operations, you cannot tell if the compiler actually did the operations in the precision of an int and then converted to a char to store in your variable, or if the operations were done in char all along.

For example, consider unsigned char = unsigned char + unsigned char + unsigned char, where addition would overflow (let's assume a value of 200 for each). If you promoted to int, you would get 600, which would then be implicitly down cast into an unsigned char, which would wrap modulo 256, thus giving a final result of 88. If you did no such promotions,you'd have to wrap between the first two additions, which would reduce the problem from 200 + 200 + 200 to 144 + 200, which is 344, which reduces to 88. In other words, the program does not know the difference, so the compiler is free to ignore the mandate to perform intermediate operations in int if the operands have a lower ranking than int.

This is true in general of addition, subtraction, and multiplication. It is not true in general for division or modulus.

0
5

If you exclude the unsigned types, there is an ordered hierarchy: signed char, short, int, long, long long, float, double, long double. First, anything coming before int in the above will be converted to int. Then, in a binary operation, the lower ranked type will be converted to the higher, and the results will be the type of the higher. (You'll note that, from the hierarchy, anytime a floating point and an integral type are involved, the integral type will be converted to the floating point type.)

Unsigned complicates things a bit: it perturbs the ranking, and parts of the ranking become implementation defined. Because of this, it's best to not mix signed and unsigned in the same expression. (Most C++ experts seem to avoid unsigned unless bitwise operations are involved. That is, at least, what Stroustrup recommends.)

2
  • 3
    Stroustrup can recommend what he likes, but using a sign-able int for a number that never needs to be negative is a complete waste of a full 50% of the available range. I'm certainly no Stroustrup, but I use unsigned by default and signed only when I have a reason. Dec 18, 2015 at 1:08
  • 2
    That's all well and good, underscore_d, until the day when you have to subtract. The primary problem with unsigned numbers in C++ is that when you perform subtraction, they stay unsigned. So suppose you write a function to see if a std::vector is in order. You might write bool in_order(vector<T> vec) { for ( int i = 0; i < size() - 1; ++i) { if (vec[i + 1] < vec[i]) return false; } return true; and then you'd be annoyed to find that it crashes for empty vectors because size() - 1 returns 18446744073709551615.
    – jorgbrown
    Feb 4, 2019 at 5:53
3

My solution to the problem got WA(wrong answer), then i changed one of int to long long int and it gave AC(accept). Previously, I was trying to do long long int += int * int, and after I rectify it to long long int += long long int * int. Googling I came up with,

1. Arithmetic Conversions

Conditions for Type Conversion:

Conditions Met ---> Conversion

  • Either operand is of type long double. ---> Other operand is converted to type long double.

  • Preceding condition not met and either operand is of type double. ---> Other operand is converted to type double.

  • Preceding conditions not met and either operand is of type float. ---> Other operand is converted to type float.

  • Preceding conditions not met (none of the operands are of floating types). ---> Integral promotions are performed on the operands as follows:

    • If either operand is of type unsigned long, the other operand is converted to type unsigned long.
    • If preceding condition not met, and if either operand is of type long and the other of type unsigned int, both operands are converted to type unsigned long.
    • If the preceding two conditions are not met, and if either operand is of type long, t he other operand is converted to type long.
    • If the preceding three conditions are not met, and if either operand is of type unsigned int, the other operand is converted to type unsigned int.
    • If none of the preceding conditions are met, both operands are converted to type int.

2 . Integer conversion rules

  • Integer Promotions:

Integer types smaller than int are promoted when an operation is performed on them. If all values of the original type can be represented as an int, the value of the smaller type is converted to an int; otherwise, it is converted to an unsigned int. Integer promotions are applied as part of the usual arithmetic conversions to certain argument expressions; operands of the unary +, -, and ~ operators; and operands of the shift operators.

  • Integer Conversion Rank:

    • No two signed integer types shall have the same rank, even if they have the same representation.
    • The rank of a signed integer type shall be greater than the rank of any signed integer type with less precision.
    • The rank of long long int shall be greater than the rank of long int, which shall be greater than the rank of int, which shall be greater than the rank of short int, which shall be greater than the rank of signed char.
    • The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type, if any.
    • The rank of any standard integer type shall be greater than the rank of any extended integer type with the same width.
    • The rank of char shall equal the rank of signed char and unsigned char.
    • The rank of any extended signed integer type relative to another extended signed integer type with the same precision is implementation-defined but still subject to the other rules for determining the integer conversion rank.
    • For all integer types T1, T2, and T3, if T1 has greater rank than T2 and T2 has greater rank than T3, then T1 has greater rank than T3.
  • Usual Arithmetic Conversions:

    • If both operands have the same type, no further conversion is needed.
    • If both operands are of the same integer type (signed or unsigned), the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
    • If the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type is converted to the type of the operand with unsigned integer type.
    • If the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type is converted to the type of the operand with signed integer type.
    • Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type. Specific operations can add to or modify the semantics of the usual arithmetic operations.
1

Whole chapter 4 talks about conversions, but I think you should be mostly interested in these :

4.5 Integral promotions [conv.prom]
An rvalue of type char, signed char, unsigned char, short int, or unsigned short int can be converted to an rvalue of type int if int can represent all the values of the source type; other-
wise, the source rvalue can be converted to an rvalue of type unsigned int.
An rvalue of type wchar_t (3.9.1) or an enumeration type (7.2) can be converted to an rvalue of the first
of the following types that can represent all the values of its underlying type: int, unsigned int,
long, or unsigned long.
An rvalue for an integral bit-field (9.6) can be converted to an rvalue of type int if int can represent all
the values of the bit-field; otherwise, it can be converted to unsigned int if unsigned int can rep-
resent all the values of the bit-field. If the bit-field is larger yet, no integral promotion applies to it. If the
bit-field has an enumerated type, it is treated as any other value of that type for promotion purposes.
An rvalue of type bool can be converted to an rvalue of type int, with false becoming zero and true
becoming one.
These conversions are called integral promotions.

4.6 Floating point promotion [conv.fpprom]
An rvalue of type float can be converted to an rvalue of type double. The value is unchanged.
This conversion is called floating point promotion.

Therefore, all conversions involving float - the result is float.

Only the one involving both int - the result is int : int / int = int

1

The type of the expression, when not both parts are of the same type, will be converted to the biggest of both. The problem here is to understand which one is bigger than the other (it does not have anything to do with size in bytes).

In expressions in which a real number and an integer number are involved, the integer will be promoted to real number. For example, in int + float, the type of the expression is float.

The other difference are related to the capability of the type. For example, an expression involving an int and a long int will result of type long int.

3
  • 2
    This is not true. On may platforms a long is "bigger" than a float but what is the type of long + float?
    – CB Bailey
    Apr 6, 2011 at 7:52
  • 1
    -1: What do you mean by biggest ? Is a float bigger than an int ? Or vice versa ?
    – Paul R
    Apr 6, 2011 at 7:52
  • 2
    Thank you for your comments. Yep the size in bytes here is of no interest at all. As it comes out, obviously putting biggest in italics is not enough to explain the answer. Anyway, it does not make sense to explain it more deeply, since now there are other, very thorough answers.
    – Baltasarq
    Apr 6, 2011 at 11:24
-3

Caveat!

The conversions occur from left to right.

Try this:

int i = 3, j = 2;
double k = 33;
cout << k * j / i << endl; // prints 22
cout << j / i * k << endl; // prints 0
1
  • 11
    That's not because of the conversion but because of operator precedence. j + i * k would result in 101. Oct 12, 2015 at 13:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.