Floating-Point Output Precision
A sticky manipulator persists for subsequent operations on the stream rather than applying only to one output statement.
Predicting a Setting That Outlives Its Line
Output formatting in C++ often depends on a setting that you change once and then forget about. A single call to change the precision of floating-point output can quietly affect every floating-point value printed after it, long after the line that made the change. Before reading the explanation, study the program below and decide what you expect each of its four output lines to print.
1234.5679
123456
1235
123456cout.precision(8)sets the precision of the stream before the first pair of output lines- The integer n is printed on both lines of the program
cout.precision(4)is the only later call that changes the setting
What do you think happens?
The program never calls precision a second time before the second line of the floating-point value. Which value does the second floating-point line print?
Reveal answer
1235
The call cout.precision(4) changes the stream's precision to 4 before the third output line, so the value 1234.56789 is printed with 4 significant digits and appears as 1235. The integer 123456 is not affected by this floating-point setting, so it prints the same way on both of its lines.
Following the Setting Value by Value
The easiest way to follow a sticky setting is to track its value at each point in the program. Think of the stream as holding a single current precision value. Each call to precision replaces that value, and each floating-point insertion reads whatever value is held at that moment. The diagram shows the two values the setting takes in the program above.
Tracing the precision state through the program
For each output line in the program, state the precision value in force and what that line prints.
- 1First precision call
The statement
cout.precision(8)sets the stream's precision to 8. Nothing has changed it yet, so this value will apply to later floating-point output. - 2First pair of output lines
The value x is printed while the precision is 8, producing 1234.5679. The integer n is printed as 123456, because the precision setting has no visible effect on an integer.
- 3Second precision call
The statement
cout.precision(4)replaces the stored value with 4. No other statement in the program sets precision, so the stream still holds the old value until this line runs. - 4Second pair of output lines
The value x is now printed while the precision is 4, producing 1235. The integer n still prints as 123456.
The four lines printed are 1234.5679, 123456, 1235, and 123456. The only line that changes is the floating-point value printed after the second precision call.
What Makes a Manipulator Sticky
A sticky manipulator persists for subsequent operations on the stream rather than applying only to one output statement. Once it is applied to a stream, its effect stays in place for the operations that follow.
Some manipulators are described as sticky, and the precision manipulator is the standard example. The call that sets precision is cout.precision(n), where n is the value you pass in. The setting it creates affects subsequent floating-point output operations, and it stays in force until the program calls precision again. That is why the program does not need to re-apply the setting before each output statement: the stream remembers it.
The word sticky is the key to predicting output. A statement that changes the precision is not only responsible for its own line of output. It also determines how every later floating-point insertion on the same stream will look, until another precision call replaces the value.
Locating Where Output Diverges
When printed output differs from what you expected, the fastest way to find the cause is to walk through the statements in order. Read from the top, and before each output statement note the most recent precision call. Then check whether the value being printed is a floating-point value. The first floating-point line printed after a precision call that differs from your expectation is usually the place where the divergence starts.
Applied to the program, the trace shows that the first floating-point line, 1234.5679, follows the setting 8 and is correct for that setting. The divergence appears on the third line of output, which prints 1235. That line is the first floating-point value printed after the precision(4) call, so the change in the setting is the cause, not the value of x. The integer line that follows it still prints 123456.
Mistakes Beginners Make with a Sticky Setting
Common mistake Assuming the precision setting applies only to the output statement that follows the call
What it looks likeAfter cout.precision(4), the programmer expects the next line only to be shortened and every later line to return to normal.
Why it failsThe precision manipulator is sticky. It persists for subsequent operations on the stream rather than applying to a single output statement.
Do this insteadTrack the most recent precision call and assume its value applies to every later floating-point insertion until another call replaces it.
Common mistake Expecting an integer to change when the precision changes
What it looks likeThe programmer changes the precision to 4 and expects the integer 123456 to print as 1235 as well.
Why it failsThe sticky precision setting affects floating-point output. The integer 123456 is not a floating-point value, so it prints the same way.
Do this insteadCheck whether each printed value is floating-point before attributing a change in its output to the precision setting.
Common mistake Re-reading the output line instead of the most recent precision call
What it looks likeA programmer sees 1235 printed and searches the output statement for the cause, when the cause is a precision call earlier in the program.
Predicting Output in a New Program
Use the same tracing method on a new program. The program below prints one floating-point value and one integer several times, with two precision calls placed between the output statements. Before you run it or read further, write down the four output lines you expect, and identify which line is the first to differ from the one before it.
Predict the four lines this program prints. Then state which line is the first floating-point value printed after a precision call and explain why the integer 42 prints the same way on both of its lines.
Hints
- Start with the precision value set by the first cout.precision call and note which output lines come after it.
- Ask whether each printed line is a floating-point value before deciding whether the precision setting can change it.
- Remember that the second precision call replaces the stored value, and no statement after it changes the setting again.
Key Takeaways
- A sticky manipulator persists for subsequent operations on the stream rather than applying only to the single output statement it appears in.
- The precision manipulator is sticky:
cout.precision(n)changes the setting for later floating-point output until the next precision call. - Integers such as 123456 are not affected by the sticky precision setting, because it applies to floating-point output.
- To find where output diverges from expectations, trace the most recent precision call before each statement and check whether each printed value is floating-point.