211

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.

Matt Montag
  • 7,105
  • 8
  • 41
  • 47

9 Answers9

276

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>
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 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? – Rafał Dowgird Apr 06 '11 at 07:59
  • More precisely: built-in operators always act on the same types. User defined-operators can mix arbitrary types, so long as at least one operand is of a user-defined type. – Drew Hall Apr 06 '11 at 08:01
  • 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. – Martin York Apr 06 '11 at 08:08
  • 1
    @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`. – Steve Jessop Apr 06 '11 at 08:27
  • @Martin: on the architecture Rafał describes, though, supposing the most efficient integer type is 8 bits then of course that can't be chosen as `int`. If we read the standard as *requiring* that all other integer types be no faster than `int`, then the compiler would have to avoid optimizations that use `char` arithmetic where it works, to slow things down. I'm pretty sure that's not the intention of the standard, it's just vague advice to implementers that if all else is equal, pick a fast type for `int`. – Steve Jessop Apr 06 '11 at 08:30
  • In practice, on a hypothetical architecture where registers are 64bit *and* 64bit arithmetic is faster than 32bit, I wouldn't be at all surprised if an implementation completely ignored the advice and kept `int` at 32 bits. You could then have an argument whether "natural size suggested by the architecture of the execution environment" in the standard is a sufficiently well-defined concept for that to be non-conforming behavior. I'd say that what architectures "suggest" is subjective enough that it doesn't bar that, it just means `int` (unlike `long`) won't gratuitously be 37 bits. – Steve Jessop Apr 06 '11 at 08:33
  • What does C99 have to do with it? This question is about C++. Say "C++0x only". – Lightness Races in Orbit Apr 06 '11 at 09:33
  • 1
    @ Tomalak Geret'kal: You have enough rep to edit the question. But its technically not part of C++ though every compiler (apart from one) the I have used provides this extension (usually its just a nice take from there C compiler). And I did not mention C++0x becuase (a) I forgot and (b) its not yet official (but mostly because I forgot). – Martin York Apr 06 '11 at 16:50
  • If either is long and the other is unsigned int, both of them will be promoted to unsigned long (same for long long). – Calmarius Jul 11 '12 at 11:37
  • @Calmarius: The version of the standard with the wording was `n2009` published on 2006-04-21. The wording changed in `n2134` published in 2006-11-03. So you are a bit out of date. But there is a grain of truth in what you say assuming that `signed type` has a larger rank than the `unsigned type` **AND** can not represent all values of the `unsigned type`. Exact wording can be found in `n3376` Section 5 `Expr` Paragraph 9. – Martin York Jul 11 '12 at 14:56
  • 7
    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 '13 at 12:53
  • 14
    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 '13 at 13:15
  • @stop-forgetting-my-accounts: Updates incorporated. – Martin York Jun 27 '14 at 04:58
  • @LokiAstari: why there is no promotion from int to long int in C++? Why this program http://ideone.com/7VHdoU fails in compilation? – Destructor Oct 20 '15 at 13:18
  • @PravasiMeet: That is a completely different question then is asked here. Also the error messages generated are very clear on why it failed `call of overloaded 'fun(int)' is ambiguous`. Maybe you should create a question that ask why it is ambiguous. PS. Remove all the deleted functions and it will work. – Martin York Oct 20 '15 at 23:58
  • The answer is different than what the C++11 spec now says. Consider when `unsigned` and `long` (both 32-bit), this answers says `long`, yet C++11 says `unsigned long`. – chux - Reinstate Monica Jan 07 '16 at 18:36
  • Many thanks for this listing. However, you need to work on your coding style (regarding compulsive alignment ;->). That's not readable -- I have to horizontally scroll. For example, you don't really need two identical columns. – Jo So Feb 13 '16 at 20:56
  • Great answer! Here is an answer I wrote elsewhere which contains a full C++ program you can use to test expressions to see what the return type is, and if it has been implicitly cast by to the compiler to something you don't intend: http://stackoverflow.com/a/43578929/4561887 – Gabriel Staples Apr 25 '17 at 01:24
  • @MartinYork what about type conversion when comparing int > float or float > int or short > int or int > short? do you have a stackoverflow.com link? – Trevor Boyd Smith Apr 04 '18 at 19:31
  • What about between float and double? – Aaron Franke May 18 '18 at 03:36
  • @AaronFranke Those are covered above. – Martin York May 18 '18 at 19:57
  • The table names an order in which the conversion happens? Meaning, the conversion higher in table overrules the one lower in table? – TStancek May 22 '18 at 08:13
  • @TStancek Yes. But it is an obvious order. You are always converting **one** operand to a larger type to prevent information loss. – Martin York May 22 '18 at 15:22
39

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 ]

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 4
    ...so long as the other type is neither `double` nor `long double`. – CB Bailey Apr 06 '11 at 07:53
  • 1
    @Charles: Correct. I quoted the relevant section from the Standard to clarify further. – Nawaz Apr 06 '11 at 07: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 '14 at 13:25
  • 1
    This answer is out-of-date. Suggest update. In particular, `long long` and `unsigned long` not addressed right here. – chux - Reinstate Monica Jan 07 '16 at 18:39
  • @MarcoA. a 32-bit `float` doesn't have enough bits in the mantissa (24 bits for [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754#Representation_and_encoding_in_memory)) for a 32-bit `int`, so there might be some data loss. A 64-bit `double` should be just fine. – Mark Ransom Jun 02 '20 at 13:55
18

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.

legends2k
  • 31,634
  • 25
  • 118
  • 222
  • 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 04 '19 at 22:43
7

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.

David Stone
  • 26,872
  • 14
  • 68
  • 84
4

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.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 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. – underscore_d Dec 18 '15 at 01:08
  • 1
    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 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 04 '19 at 05: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.
garakchy
  • 554
  • 10
  • 19
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.

Baltasarq
  • 12,014
  • 3
  • 38
  • 57
  • 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 06 '11 at 07:52
  • 1
    -1: What do you mean by *biggest* ? Is a float *bigger* than an int ? Or *vice versa* ? – Paul R Apr 06 '11 at 07: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 06 '11 at 11:24
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

BЈовић
  • 62,405
  • 41
  • 173
  • 273
-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
Habib
  • 472
  • 4
  • 9