Summary
This lesson opens the third unit of the course, devoted to expressions and their operators. It explains what the unit is for: to teach how to build expressions whose value can be predicted with certainty, knowing which operation is performed first, what type the result has, what side effects they have and which expressions have no meaning; it presents its four lessons and the thread that joins them, from integer and real arithmetic to bits and the math library, by way of conditions and the catalog of undefined behavior; it recalls what the unit takes for granted from the second, namely the type of each piece of data, its limits and its conversions; it formulates the problem the unit solves, that of a program that compiles without a single warning and whose answers to six school questions are all wrong, when they are not missing altogether; and it shows where it leads, in the following units and in the course Programming in C++ II.
Learning objectives
- Describe the sequence of contents of the unit and explain what each lesson contributes to the next.
- Recall what is needed from unit 2 (the integer and real types, their ranges, overflow and conversions) and review it if necessary.
- Anticipate, with an example, that the value of an expression depends on evaluation rules (precedence, the type of the operands, the order of the effects) that do not always coincide with those of school mathematics.
- Recognize what one is expected to be able to do at the end of the unit, and distinguish it from what will be learned in the following units.
Entry assessment
Before working through the unit, it is worth measuring the starting point. This assessment is a self-assessment: it is not graded, and its only purpose is to guide your study. The first four questions check what the unit takes for granted from the second: division between integers, writing in base 2, unsigned subtraction and signed overflow. The next six touch, in the order of the lessons, on the central ideas of the unit, and several of them start from school mathematics or from elementary logic. No one is obliged to get them right yet, and in two of them “I don’t know yet” is an honest answer: each answer, right or not, explains the point and names the lesson that deals with it. The same skills are measured again at the end, in the synthesis lesson.
Before starting the unit, measure your starting point. It is a short self-assessment: it is not graded and its result is stored only in your browser.
Question 1From earlier unitsA program declares
const double r{7 / 2};and writesr. What appears?Believes that the type of the variable decides how the division is done; the type of the operands decides it.Believes that integer division rounds; it discards the fractional part.The value 3 is constant and is represented exactly in adouble: there is no narrowing to reject.The division7 / 2is between integers and gives the integer quotient, 3; only afterwards is that 3 converted todouble. The type of the operands decides the operation, not the type of the variable that receives the result. Lesson 3.1 turns this observation into a general rule: the type is decided at each node of the expression.Question 2From earlier unitsHow is the number 13 written in base 2, with eight bits?
Adds the weights incorrectly: .Writes the remainders of the repeated divisions in the order in which they come out; they are read from the last to the first.That pattern is 26, twice 13: the bits are shifted by one position.Each position weighs twice as much as the one to its right: the ones occupy the positions of weight 8, 4 and 1. Lesson 3.4 operates directly on these bits, so it is worth reading them fluently.Question 3From earlier unitsWhat does
std::println("{}", 0u - 1);write with a 32-bitunsigned int?Does not take the suffixuinto account: an unsigned type has no negative values.Confuses unsigned arithmetic, defined modulo , with signed overflow.Believes that the subtraction stops at the smallest value of the type; it wraps around.Unsigned arithmetic is modulo : . The result is defined, and that is why no sanitizer flags it. The unit meets it again in the conversions of a mixed expression and in the bitwise operators, which are written with unsigned types.Question 4From earlier unitsA program executes
int count{std::numeric_limits<int>::max()};and thencount = count + 1;. What does the standard guarantee about the value ofcount?Confuses what is sometimes observed with what the standard guarantees; wrapping around to the minimum is what unsigned types do, not signed ones.Ignores the limit of the type: that number does not fit in a 32-bitint.The compiler does not know the values the program will have when it runs; it almost always compiles without saying anything.The addition has a precondition, that the result fit in the type, and outside it the standard promises nothing. The course sanitizer stops the program; without it, anything may be written. Lesson 3.3 gathers this case with the others of its kind in a catalog.Question 5What are the values of and ?
Operates from left to right without heeding the precedence of the product.Ignores the parentheses of the second expression.Attributes to each expression the value of the other: inverts the effect of the parentheses.The product binds more tightly than the sum: in the multiplication is done first, and the parentheses alter that order. C++ follows the same convention, and lesson 3.1 extends it to division, to the remainder and to associativity, with the tree of the expression as its instrument.Review: Arithmetic
Question 6According to the division theorem of mathematics, with the remainder subject to , what are the quotient and the remainder of divided by ?
That is what C++ computes, but it does not satisfy : the remainder of mathematics is not negative.Does not check the identity: , not .It does not satisfy the identity either: .The theorem requires with , and those two numbers are the only ones that satisfy it. C++, by contrast, truncates the quotient toward zero:-7 / 2is and-7 % 2is . Lesson 3.1 explains the difference and teaches how to obtain the remainder of mathematics from that of C++.Review: Arithmetic
Question 7What is the negation of “it is raining and it is cold”?
Negates each part without changing the connective: that asserts much more than the negation, because it also excludes the dry, cold day.Negates only one of the parts.Says the same as the second option, with the same error.The negation of a conjunction is the disjunction of the negations: it is one of De Morgan’s laws. It is enough for one of the two things to be missing for the statement to be false. Lesson 3.2 applies the same law to the conditions of a program.Review: Relations and logic
Question 8What does
std::println("{}", 3 < 5);write?Believes that the truth value is written as a number; with the placeholder{},std::printlnwrites the word.Believes that the expression is written as text; what is written is its value.It is: a comparison is an expression of typebool.A comparison is an expression like any other: it has a value, of typebool, andstd::printlnwrites it astrueorfalse. Lesson 3.2 starts from this observation: a condition is computed, and that is why it has precedence, a tree and an algebra.Review: Relations and logic
Question 9After
int a{5};andint b{a++ * 2};, what are the values ofaandb?It is an honest answer: lesson 3.3 teaches the difference between the value of an expression and its effect, and the exit assessment will ask it again.Forgets the effect:a++incrementsa.Uses the new value ofa; the postfix increment yields the previous value.The expressiona++has a value, the oneahad (5), and an effect, which leavesaat 6. The product uses the value, not the effect. Lesson 3.3 teaches how to separate the two, and how to recognize when two effects in the same expression leave it without meaning.Question 10What does
std::println("{}", 2 ^ 3);write?It is an honest answer: lesson 3.4 explains it, and the exit assessment will ask it again.Reads the caret as exponentiation, as in the notation of many calculators; in C++ it is not.Reads it as a product.In C++ the caret is not exponentiation, but the bitwise XOR: and differ only in the bit of weight 1, so the result is 1. C++ has no exponentiation operator; lesson 3.4 teaches when to usestd::powand when a shift.Review: Bits and the math library
Loading the content…
Completed
Sign in to save your progress