Concepts / Arithmetic Operators in C++

Arithmetic Operators in C++

Two settings trigger conversions: arithmetic operations, where values are combined with an operator, and assignments, where a value is stored into a variable. Both the operands and the receiving variable therefore matter.

  • Programming

A Cost Calculation with Two Types

Suppose you are writing a small program that calculates the cost of some items. The number of items is a whole number, while the price of each item may include cents. In a real program these two values often live in variables of different basic types, and you want to combine them in one arithmetic expression. The question for this article is simple: when you use an arithmetic operator on values of different types, what does C++ do?

What do you think happens?

Suppose items holds the whole number 3 and price holds the fractional value 2.25. What does the expression items * price produce?

Reveal answer
Answer:

6.75

The int value 3 is brought into agreement with the double value 2.25, the multiplication is carried out on doubles, and the result 6.75 keeps the fractional part.

Why Mixed Types Can Work at All

Arithmetic operators such as addition, subtraction, multiplication, and division are not attached to one single type. They work with the basic types, and they work with combinations of those types where the combination makes sense for the calculation. The word appropriate matters: the operator is not a blanket permission for every pairing of values.

The reason a mixed expression can work at all is that C++ performs all meaningful conversions between the basic types so that they can be mixed freely. The language is willing to bring values of different basic types into agreement so the operation can proceed. Mixing types is therefore a supported language feature. The key question is always whether the combination is meaningful for the calculation you are doing.

Key point

Two settings trigger conversions: arithmetic operations, where values are combined with an operator, and assignments, where a value is stored into a variable. Both the operands and the receiving variable therefore matter.

Tracing a Mixed Expression Step by Step

Return to the opening calculation. One variable holds a whole number of items, and another holds a price with a fractional part. The program below multiplies them and stores the result in a third variable. Read the code first, then compare it with the prediction you made earlier.

Code walkthrough
#include <iostream>

int main() {
    int items = 3;
    double price = 2.25;
    double total = items * price;
    std::cout << total << std::endl;
    return 0;
}
  1. 1
    Line 4 creates the int variable items with the value 3.
  2. 2
    Line 5 creates the double variable price with the value 2.25.
  3. 3
    Line 6 evaluates items * price. Because one operand is a double, the int 3 is converted so the multiplication can proceed on doubles.
  4. 4
    The multiplication produces 6.75, and that double value is assigned to total.
  5. 5
    Line 7 prints total, which shows 6.75.
  • items is an int holding the whole number 3
  • price is a double holding the fractional value 2.25
  • items * price mixes an int operand with a double operand
  • total is a double, so the stored result keeps its fractional part
Output
6.75
itemsint, value 3Convert int operand3 becomes 3.0Multiply3.0 * 2.25Resultdouble, value 6.75totaldouble variablepricedouble, value 2.25int to doubledouble operanddouble operanddouble resultassigned
When an int and a double meet in one expression, the int operand is converted to a double, the multiplication runs on two doubles, and the double result is stored in total.

Notice that the example involves two steps where conversion matters: the operation itself and the assignment that stores its result. Both situations are covered by the same idea of free mixing. The conversion of the int operand happens so the multiplication has a common type to work with, and the assignment then stores the double result into total without changing it.

Conversion During Assignment

Assignment is the second setting where conversions happen. When a value of one basic type is assigned to a variable of another basic type, C++ performs a conversion so the assignment can happen. The idea is that conversion puts a value into a form the destination variable can hold.

Code walkthrough
#include <iostream>

int main() {
    int whole = 7.9;
    std::cout << whole << std::endl;
    return 0;
}
  1. 1
    Line 4 assigns the double value 7.9 to the int variable whole.
  2. 2
    Because whole is an int, the fractional part is dropped and the stored value is 7.
  3. 3
    Line 5 prints 7, not 7.9.
  • The initializer 7.9 is a double
  • whole is an int, so it cannot hold a fractional part
  • The stored value is 7
Output
7
Value 7.9doublewholeint, value 7assigned
The double value 7.9 is assigned to the int variable whole, and the stored value becomes 7. The fractional part is not kept.

The stored value is the destination's representation of the source, not the original number. An int has no place for a fractional part, so the value that arrives in whole is 7. Keep this in mind whenever a double result flows into an int variable.

Integer and Floating-Point Division

The operand types decide how a division is carried out. When both operands are int, C++ performs integer division and the fractional part of the quotient is discarded. When one operand is a double, the division is carried out on doubles and the fractional part is kept. The same symbol, /, therefore produces different answers depending on the types of its operands.

Code walkthrough
#include <iostream>

int main() {
    std::cout << 7 / 2 << std::endl;
    std::cout << 7 / 2.0 << std::endl;
    return 0;
}
  1. 1
    Line 4 divides two int literals, so the result is the int 3.
  2. 2
    Line 5 divides the int 7 by the double 2.0. The int is converted to a double, and the result is 3.5.
  • 7 / 2 has two int operands
  • 7 / 2.0 has one double operand
  • The literal 2.0 is a double, which changes the kind of division
Output
3
3.5
7 / 2int and int3int result7 / 2.0int and double3.5double resultinteger divisionfloating-point division
Two divisions that look almost identical produce different results because one has int operands and the other has a double operand.

Operators That Need Specific Types

Because the word appropriate matters, not every operator accepts every pairing. The remainder operator % is defined for integer operands. Asking it to work on a double is a combination that does not make sense for that operator, so the program does not compile.

Mistakes Beginners Make with Mixed Types

  • Common mistake

    Assuming 7 / 2 gives 3.5 because the program is doing arithmetic on decimal values

    What it looks like
    std::cout << 7 / 2 << std::endl; prints 3
    Why it fails

    Both operands are int, so C++ performs integer division and discards the fractional part.

    Do this instead

    Use a double operand, such as 7 / 2.0, when the fractional result is needed.

  • Common mistake

    Assuming a double result stored in an int keeps its fractional part

    What it looks like
    int whole = 7.9; leaves whole holding 7
    Why it fails

    An int cannot hold a fractional part, so the conversion during assignment drops it.

    Do this instead

    Store the result in a double if the fractional part must be kept, or decide explicitly how the value should be reduced.

  • Common mistake

    Assuming every operator accepts every type combination the same way

    What it looks like

    Using % with a double operand, as in 7.5 % 2

    Why it fails

    The remainder operator is defined for integer operands, so this combination does not compile.

    Do this instead

    Check that the operator is defined for the operand types before writing the expression.

  • Common mistake

    Predicting results from the look of the numbers instead of from the types of the operands

Practice Predicting Mixed-Type Results

MEDIUM

Before running any code, predict the output of each line: (1) std::cout << 9 / 4 << std::endl; (2) std::cout << 9 / 4.0 << std::endl; (3) int n = 4.6; std::cout << n << std::endl;. For each one, name the types of the operands or the variable that receives the value, and say whether the fractional part survives.

Hints
  • Look at whether both operands of the division are int or whether one is a double.
  • For the assignment, ask what an int variable can store.
  • Check the operand types first, then the result.

Key Takeaways

  • C++ performs all meaningful conversions between the basic types so that they can be mixed freely in arithmetic and assignment.
  • Arithmetic operators work with appropriate combinations of types, so the key question is whether the combination is meaningful for the calculation.
  • When an int and a double meet in one expression, the int operand is converted so the operation runs on a common type, and the double result can then be stored.
  • Assigning a double to an int converts the value, and the fractional part is dropped.
  • Two divisions that look alike can differ: 7 / 2 gives 3 with int operands, while 7 / 2.0 gives 3.5 with a double operand.

Related concepts

More concepts starting with A