A number in a program has both a value and a type. The value might be 5; the type tells C++ what kind of value it is and how operations on it work. This matters even for a familiar calculation such as division.
Counts often use int, measurements often use double, a single character uses char, and a condition uses bool. An integer count can represent five observations. A double can represent a measurement such as 5.25. A character holds one code unit, such as a letter in simple text. A Boolean holds true or false. Choose a type to match the data, then check its range and precision.
Give a variable a starting value #
The statement int count{0}; declares a variable and initializes it to zero. Declaring introduces the name and type. Initializing gives the object its first value. Later, count = 4; replaces the stored value with four.
Assignment goes from right to left: evaluate the expression on the right, then store the result in the object on the left. In count = count + 1, a count of four is read, one is added, and five is stored back. The statement changes a value; it is not an algebraic claim that four equals five.
A local built-in number declared without initialization does not automatically start at zero. Give it a value before reading it. Names such as distance_km also help keep the meaning and unit visible. One declaration per line is useful when the variables serve different purposes.
Why integer division loses the fraction #
Multiplication and division take precedence over addition and subtraction. Parentheses can state the intended grouping. For nonnegative integers, division finds the whole-number quotient, and % finds the remainder. Dividing 17 by 5 gives quotient 3 and remainder 2: three groups of five use fifteen, leaving two.
The type of the operands matters. When both operands are integers, division discards the fractional part.[1] A double variable receiving the answer cannot recover what was already discarded. Follow that distinction through this program.
#include <iostream>
int main() {
const int total = 17;
const int count = 5;
const double wrong = total / count;
const double mean = static_cast<double>(total) / count;
std::cout << wrong << ' ' << mean << '\n';
}First, total receives integer 17 and count receives integer 5. Next, the expression used to initialize wrong divides those two integers. It produces integer 3. Only after that division does C++ convert the result to double for storage. The stored value is 3.0, not 3.4.
The next declaration uses static_cast<double>(total) / count. The cast converts the total to double before the division. The division now uses floating-point arithmetic and produces approximately 3.4. That result initializes mean. The output sends wrong, a separating space, mean, and a newline to the console, displaying 3 3.4 with the default formatting.
A cast is a requested conversion. It does not make any value or operation valid automatically. Converting a fractional measurement to an integer loses its fractional part. A zero divisor remains a problem even if an operand is converted to double.
Precision is different from formatting #
A floating-point number can store many useful measurements, but it has limited precision. Some decimal fractions do not have an exact representation in the machine's floating-point format. Small rounding differences can therefore appear, particularly after repeated calculations.
Displaying two decimal places changes how a value looks. It does not change the stored measurement into an exact number with only two decimal digits. When comparing a computed value with an expected result, choose a tolerance appropriate to the problem rather than assuming the two values must match exactly.
For example, if the expected value is 10 and the computed value is 9.8, the absolute error is the magnitude of their difference, 0.2. Relative error divides that error by the magnitude of the nonzero expected value. Here it is 0.2 divided by 10, or 0.02. Multiplying by 100 gives 2 percent.
An expected value of zero cannot be used as the denominator of relative error. In that case use an appropriate absolute-error check. Also distinguish error size from its direction: an absolute error describes how far apart the values are, not which is larger.
Integers have limits too #
Machine integers cannot represent every mathematical integer. Signed integer overflow is undefined behavior in C++; it is not a reliable way to obtain a wrapped result. These examples use small inputs whose calculations fit their types.
The place where a conversion happens still matters for range. In static_cast<double>(n) * n, conversion happens before multiplication, avoiding an integer multiplication overflowing first. This does not promise unlimited floating-point range or exactness; it only changes which arithmetic operation is performed.
Similarly, in static_cast<double>(finish - start) / start * 100.0, the subtraction happens before the cast. The difference must fit its integer type, and start must be a valid nonzero baseline. Check both requirements rather than treating the cast as a general repair.
Practice with explained answers #
Predict 9 / 2, 9 % 2, and 9 / 2.0. The first divides integers, producing 4. The remainder is 1 because four groups of two account for eight. The third has a double operand and produces 4.5.
For a starting count of 80 and a finishing count of 100, the increase is 20. The percentage increase is 20 divided by 80, multiplied by 100, giving 25 percent. Integer division before conversion would incorrectly discard that fraction. Use the cast before division, with the baseline and difference checks described above.
This arithmetic prepares the means and percentage changes in CS2 Lectures 3 and 4 and Lab 1. The same attention to operation order matters for the quadratic calculations in Lab 4.