Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Formatting Numbers with C++ Output Streams: Controlling Numeric Output in C++, Lecture notes of C programming

An overview of how to control the format of numeric output using C++ output streams. It covers the use of member functions and manipulators to change various member variables that affect the appearance of numbers. The document focuses on controlling the format of integers and doubles, saving and restoring stream settings, and using fixed format for neat output.

What you will learn

  • How can I save and restore stream settings in C++?
  • What is the difference between fixed and general floating-point formats in C++?
  • How can I control the minimum number of characters used to print a number in C++?

Typology: Lecture notes

2021/2022

Uploaded on 09/12/2022

eklavya
eklavya 🇺🇸

4.5

(22)

266 documents

1 / 9

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Formatting Numbers with C++ Output Streams
David Kieras, EECS Dept., Univ. of Michigan
Revised for EECS 381, Winter 2004.
Using the output operator with C++ streams is generally easy as pie, with the only hard part being controlling the format of
the output. As you will see, this is relatively clumsy compared to C stdio's printf function, but printf is not type-safe. An
output stream has a bunch of member variables that control the details of what output looks like, and these variables can be
controlled by a set of member functions and special objects called manipulators. Most of these variables retain their values
until they are changed, but a few only act temporarily - for the next output operation only.
Throughout this document, the output stream cout is used in the examples. However, everything works for any text output
stream, such as an output file stream.
The prototypical output statement in C++ is:
cout << "Hello, world!" << endl;
This contains a manipulator, endl. This is an object, which when supplied to operator<<, causes a newline character to
be put into the output stream, followed by a call of cout's flush function, which causes the internal buffer to be immediately
emptied. This makes sure all of the output is displayed before the program goes on to the next statement. So manipulators are
objects that cause the output stream object to do something, either to its output, or to its member variables.
The manipulators with no arguments, like endl, are included in <iostream>. If you use manipulators that take arguments
(like setprecision and setw) you need to #include <iomanip>.
Like the input operator, operator<< has overloaded definitions for all of the built-in types. By default, characters and
strings are simply output as is, and this is usually satisfactory. So the main complexity is controlling the format of numbers.
There are a zillion variables that control numeric and other formats. This document focuses on how to control the most
important and common aspects of numeric output.
You can control the format by using member functions or manipulators to change a variety of member variables. This
document summarizes the most important and common things you might want to do; check a complete reference to do more.
Quite a few things can be done with the stream formatting controls, and not just with numbers; if you find yourself tempted to
write complicated code to make the output look neat, stop and consult a good reference first - you might be about to reinvent
the wheel.
Default output format for integers and doubles
All of the digits of an integer will be printed using decimal (base 10), with no leading zeros and a leading minus if it is
negative, using as many characters as needed, but no more.
A double value will be printed using a general format that usually works fine to represent a number in a small amount of
space. The basic amount of space used is determined by the precision. The default precision is 6, which means up to 6
significant digits are used to represent the number. This counts digits both to the left and the right of the decimal point. Fewer
digits are printed if the result is accurate; e.g. trailing zeros at the right of the decimal point are not printed. As shown in the
example below, as the number increases in size, places to the right of the decimal point will be dropped, and the result
rounded off as needed to stay within 6 digits. If the number cannot be represented with six digits to the left of the decimal
point after all to the right have been dropped, the output will flip into exponential (scientific) notation showing 6 significant
1
pf3
pf4
pf5
pf8
pf9

Partial preview of the text

Download Formatting Numbers with C++ Output Streams: Controlling Numeric Output in C++ and more Lecture notes C programming in PDF only on Docsity!

Formatting Numbers with C++ Output Streams

David Kieras, EECS Dept., Univ. of Michigan

Revised for EECS 381, Winter 2004.

Using the output operator with C++ streams is generally easy as pie, with the only hard part being controlling the format of

the output. As you will see, this is relatively clumsy compared to C stdio's printf function, but printf is not type-safe. An

output stream has a bunch of member variables that control the details of what output looks like, and these variables can be

controlled by a set of member functions and special objects called manipulators. Most of these variables retain their values

until they are changed, but a few only act temporarily - for the next output operation only.

Throughout this document, the output stream cout is used in the examples. However, everything works for any text output

stream, such as an output file stream.

The prototypical output statement in C++ is:

cout << "Hello, world!" << endl;

This contains a manipulator , endl. This is an object, which when supplied to operator<<, causes a newline character to

be put into the output stream, followed by a call of cout's flush function, which causes the internal buffer to be immediately

emptied. This makes sure all of the output is displayed before the program goes on to the next statement. So manipulators are

objects that cause the output stream object to do something, either to its output, or to its member variables.

The manipulators with no arguments, like endl, are included in . If you use manipulators that take arguments

(like setprecision and setw) you need to #include .

Like the input operator, operator<< has overloaded definitions for all of the built-in types. By default, characters and

strings are simply output as is, and this is usually satisfactory. So the main complexity is controlling the format of numbers.

There are a zillion variables that control numeric and other formats. This document focuses on how to control the most

important and common aspects of numeric output.

You can control the format by using member functions or manipulators to change a variety of member variables. This

document summarizes the most important and common things you might want to do; check a complete reference to do more.

Quite a few things can be done with the stream formatting controls, and not just with numbers; if you find yourself tempted to

write complicated code to make the output look neat, stop and consult a good reference first - you might be about to reinvent

the wheel.

Default output format for integers and doubles

All of the digits of an integer will be printed using decimal (base 10), with no leading zeros and a leading minus if it is

negative, using as many characters as needed, but no more.

A double value will be printed using a general format that usually works fine to represent a number in a small amount of

space. The basic amount of space used is determined by the precision. The default precision is 6, which means up to 6

significant digits are used to represent the number. This counts digits both to the left and the right of the decimal point. Fewer

digits are printed if the result is accurate; e.g. trailing zeros at the right of the decimal point are not printed. As shown in the

example below, as the number increases in size, places to the right of the decimal point will be dropped, and the result

rounded off as needed to stay within 6 digits. If the number cannot be represented with six digits to the left of the decimal

point after all to the right have been dropped, the output will flip into exponential (scientific) notation showing 6 significant

digits and the exponent of 10. You can increase or decrease the precision, and this will change the number of significant digits

shown in the output.

The problem with the general format is that if you want to make numbers line up in neat columns, as in a table of data, the

general format works very poorly because the total number of characters, and the number of digits to the right of the decimal

point, will vary depending on the size of the number. The rest of this handout descri bes the basic techniques for controlling

the format to produce neat-looking output.

Saving and restoring stream settings

First, if you are going to change the format settings of the stream, you normally will want to restore them to what they were

before you changed them, so that different parts of your program will not interfere with each other. You can get the current

settings (called "flags") from the output stream with a member function named flags. The settings can be stored in a type of

object called a fmtflags object, defined in a class called ios, which is included with . You can declare one of

these objects, but you have to declare it using the scope resolution operator. To make a long story short, the following

statement will save certain aspects of the format state in the variable old_settings:

ios::fmtflags old_settings = cout.flags();

Ugly! Then, after doing the output using the new setting, you can restore the old setting by calling the same function with the

old settings as an argument:

cout.flags(old_settings);

Other settings can be obtained and restored with member functions. For example,

int old_precision = cout.precision();

will save the current precision specification. Then

cout.precision(old_precision);

will restore the precision to the original value.

Controlling minimum field width

You can control the minimum number of characters used to print the number by specifying the field width. Leading blanks

will be included to fill up the field, but if the number doesn't fit, the extra digits will be printed regardless of the field width.

The field width also affects output of strings.

Important: Field width changes are only temporary; they affect only the next relevant output. Changing the width affects

only the immediately following output of a number, whereupon the width setting automatically reverts to the standard

behavior of "as many characters as needed" (specified by a field width of zero).

For example:

cout << "" << setw(4) << 12 << "" << endl; // manipulator

will produce:

There are two spaces between the '' and the '1' for a total of 4 characters between the ''s.

cout.setf(ios::fixed, ios::floatfield);

Fortunately, you can select the fixed format with a simple manipulator:

cout << fixed;

You can reset the floating-point format flags to the default with

cout.setf(0, ios::floatfield);

but usually you will want to restore the previous settings.

An Example of Controlling Numerical Output Format

In the following examples, we compute the valaue of pi raised to various negative and positive powers, and output the

exponent and the result. The example shows the effects of setting precision, then what we get when we set the fixed format

and then use different precisions and output widths. By using a big enough field width to cover the range of values with a

fixed format, we can get a neat tabular output result. The example saves and restores the default settings as an example. Each

batch of output has been pasted into the code as a comment with some discussion to make the example easier to follow. This

code has also been posted in the examples section of the course web site.

#include #include // needed to use manipulators with parameters (precision, width) #include ! // needed for pow function using namespace std; int main () { ! const int beginvalues = -10; ! const int endvalues = 16; ! const int nvalues = endvalues - beginvalues; ! ! int ipow[nvalues];! ! double ary[nvalues];! // an array for demo values ! ! int ipowindex = 0; ! // fill array with interesting range of values ! for (int i = beginvalues; i < endvalues; i++) { !! ipow[ipowindex] = i; !! ary[ipowindex] = pow(3.14159265, i); !! ipowindex++; !! } !! ! // output index and array[index] using default settings ! cout << "Output using default settings" << endl; ! for (int i = 0; i < nvalues; i++) !! cout << ipow[i] << ' ' << ary[i] << endl; /* Output using default settings -10 1.06783e- -9 3.35468e- -8 0. -7 0. -6 0. -5 0. -4 0.

13 2.90368e+ 14 9.12217e+ 15 2.86581e+ Each output double value has either six significant digits or fewer if the value can be expressed just as accurately. For example, for ipow = 0, the value of one shows with no decimal places and not even a decimal point. These are not printed in the default format unless there are non-zero places printed to the right of the decimal point. See also ipow = 10 through 12, where the decimal places have all been rounded off. At i = 13 and beyond, 6 digits are not enough, so the output flips into scientific notation, still showing six significant digits, but with an exponent of ten. A different rule, not so easy to state, governs when small values flip into scientific notation. /!! ! // save the current settings ! ios::fmtflags old_settings = cout.flags(); //save previous format flags ! int old_precision = cout.precision();! // save previous precision setting ! // don't need to save width setting, because it automatically resets to default value ! // after each numeric output item. ! ! // just change the precision ! cout << setprecision(8); ! cout << "\nOutput using integers with default output" << endl; ! cout << "doubles in general format, precision 8" << endl; ! for (int i = 0; i < nvalues; i++) !! cout << ipow[i] << ' ' << ary[i] << endl; ! / Output using integers with default output doubles in general format, precision 8 -10 1.0678279e- -9 3.3546804e- -8 0. -7 0. -6 0. -5 0. -4 0. -3 0. -2 0. -1 0. 0 1 1 3. 2 9. 3 31.

is messed up because the results will not fit into the total space of 8 characters (the decimal point counts as one space). Note that setting fixed format prevents the flipping into scientific notation, and forces the value of exactly one to show with a decimal point and the specified number of places to the right of the decimal point. / ! cout << "\nOutput using integers with width 3 integers, " << endl; ! cout << "doubles in fixed format, precision 0, width 5" << endl; ! // can use manipulators to change precision and others inside an output statement ! // in fixed format, precision of zero means no decimal places ! for (int i = 0; i < nvalues; i++) ! cout << setw(3) << ipow[i] << ' ' << setprecision(0) << setw(5) << ary[i] << endl; / Output using integers with width 3 integers, doubles in fixed format, precision 0, width 5 -10 0 -9 0 -8 0 -7 0 -6 0 -5 0 -4 0 -3 0 -2 0 -1 0 0 1 1 3 2 10 3 31 4 97 5 306 6 961 7 3020 8 9489 9 29809 10 93648 11 294204 12 924269 13 2903677 14 9122171 15 28658145 This gives room for the negative integer values, and so it produces a neat output until ipow = 11, whereupon the output takes additional digits just as in the previous example. Because the fixed precision is zero, everything is rounded to the nearest integer value, and thus neither a decimal point nor places to the right of the decimal point appear. For values less the one, of course, the result rounds off to zero. / ! cout << "\nOutput using integers with width 3 integers, " << endl; ! cout << "doubles in fixed format, precision 8, width 18" << endl; ! cout << setprecision(8); ! for (int i = 0; i < nvalues; i++) !! cout << setw(3) << ipow[i] << ' ' << setw(18) << ary[i] << endl; !! / Output using integers with width 3 integers, doubles in fixed format, precision 8, width 18 -10 0. -9 0.

This output is the first that is completely neat over the whole range of values. The width for the doubles leaves enough room for the additional digits to the left of the decimal point. Of course, the precision of 8 produces a lots of decimal places which we may not need. /! !! ! // restore output format flags and precision ! cout.flags(old_settings); ! cout.precision(old_precision); ! cout << "\nOutput using original settings" << endl; ! for (int i = 0; i < nvalues; i++) !! cout << ipow[i] << ' ' << ary[i] << endl; / Output using original settings -10 1.06783e- -9 3.35468e- -8 0. -7 0. -6 0. -5 0. -4 0. -3 0. -2 0. -1 0. 0 1 1 3. 2 9. 3 31. 4 97. 5 306. 6 961. 7 3020. 8 9488. 9 29809.