Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C++ For Mathematicians (2006) [eng]

.pdf
Скачиваний:
193
Добавлен:
16.08.2013
Размер:
31.64 Mб
Скачать

306

 

C++ for Mathematicians

 

 

 

 

 

Type something -->123

 

 

 

 

 

 

 

 

 

 

 

We read the character ’1’

 

 

 

 

 

 

 

’2’

 

 

 

 

 

We read the character

 

 

 

 

 

 

Type something -->

123

 

 

 

 

 

 

 

 

 

 

 

We read the character ’1’

 

 

 

 

 

 

 

 

 

 

 

 

 

We read the character ’2’

 

 

 

 

 

 

Type something --> 1

2

3

 

 

 

 

 

 

 

 

 

We read the character ’1’

 

 

 

 

 

 

We read the character ’ ’

 

 

 

 

 

 

 

 

 

In the first execution, the cin >> ch; statement reads the character 1 and then the cin.get(ch); reads the character 2. The same thing happens in the second execution because cin >> ch; skips the white spaces before the 1. However, in the third run, the statement cin.get(ch); reads the space character immediately following the 1.

There is also a put method for output streams; it is used to write a single character. If ch is a char variable, the statement cout.put(ch); is tantamount to cout << ch;.

Suppose word is a string variable. The statement cin >> word; skips white space before reading data into the variable word, and then stops as soon as additional white space is encountered. For example, the user types

Suppose $f$ is

continuous.

then the statement cin >> word; puts Suppose into the variable word. If the statement is executed repeatedly, it would subsequently save the string $f$, then is, and then continuous. into word.

Sometimes it is useful to read a full line of text into a string variable. There are two ways to do this. In both cases the procedure invoked is named getline.

We may write cin.getline(buffer, nchars); where buffer is a character array (type char*) and nchars is a positive integer. This statement reads at most nchars characters from cin and loads them into the character array buffer. The reading stops either when the end of the line is encountered or nchars have been read. Here is how this method might be used in a program.

const int MAX_LINE = 10000; char buffer[MAX_LINE]; cout << "Type a line: ";

cin.getline(buffer,MAX_LINE);

cout << "You typed: " << buffer << endl;

The drawbacks to this form of getline are (a) one needs to know a priori an upper bound on the number of characters in a line and (b) the characters are saved in a character array.

The following alternative version of getline is more convenient. The statement getline(cin,theLine); (where theLine is a string variable) reads characters from cin until reaching the end of the line; the characters are saved in theLine.

Strings, Input/Output, and Visualization

307

Both forms of getline take an optional additional argument: a char value specifying a delimiter character. Then, instead of reading to the end of the line, getline reads until the delimiter character is encountered. For example, the statement getline(cin,theLine,’/’); reads characters into theLine until a / character is encountered.

14.5String streams

C++ provide a means to treat character strings in a manner akin to file streams. Objects of the classes istringstream and ostringstream may be used in the same manner as input and output file streams, but their data come from (or go to) a string embedded in the object. The use of these classes requires a #include <sstream> directive.

An istringstream is initialized with a string or a char* array. For example,

string line("angle 70.3 degrees"); istringstream is(line);

We can now use is just as we would any other input stream object. The subsequent code

string s1; is >> s1; double x; is >> x; string s2; is >> s2;

places the string angle into s1, the value 70.3 into x, and the string degrees into s2.

It’s important that the variable receiving data from an istringstream via the >> operator be of the appropriate type. No error is reported in this situation, but the contents of the variable are unpredictable.

An ostringstream behaves in the same manner as an output stream, but the data it is sent are saved into a string, not a file. We declare an ostringstream variable without any arguments like this:

ostringstream os;

and then we send data using the usual << operator: os << k;. After we have finished putting data into os we extract the string we built using the str() method. The following code illustrates these ideas.

308

C++ for Mathematicians

Program 14.7: A program to illustrate the use of string streams.

1 #include <iostream>

2#include <sstream>

3using namespace std;

4

5int main() {

6ostringstream os;

7

8os << "The base-ten digits are";

9 for (int k=0; k<=9; k++) os << " " << k;

10os << endl;

11cout << os.str();

12

 

 

 

13

string words(" 3.9

10 hello

good bye");

14istringstream is(words);

15double x;

16is >> x; // 3.9

17int n;

18is >> n; // 10

19string s;

20is >> s; // hello

21long k;

22is >> k; // good

23cout << "x = " << x << ", n = " << n << ", s = " << s

24<< ", and k = " << k << endl;

25

26return 0;

27}

Here is the output from the program.

The base-ten digits are 0 1 2 3 4 5 6 7 8 9x = 3.9, n = 10, s = hello, and k = 0

14.6Formatting

The statement cout << x; prints the value held in x on the computer’s screen. If x is a double variable, the output may look like one of these.

Value

Comment

0.142857

decimal value of 1/7

1.42857

10/7

 

 

0.00142857

1/700

 

-0.142857

−1/7

10

11

2.5e+11

2.5 ×

 

1

one

 

 

Strings, Input/Output, and Visualization

309

Notice that the number of decimal places displayed varies, but in each case at most six significant digits are given (not counting leading zeros). Also observe that positive numbers do not have a leading + sign, and that the decimal point is dropped when x holds an integer value.

In most cases, the default behavior of cout << x; is adequate for mathematical purposes. However, we may wish to print more than six significant figures or print out a table with figures nicely arranged in columns. To accomplish these, we need to modify the default behavior of the output stream.

A convenient way to do this is through the use of manipulators that we send to output streams using the << operator. Before we may use manipulators, we need the directive #include <iomanip> at the beginning of the program.

14.6.1 Setting precision

By default, real numbers sent to an output stream (such as cout) are printed with six decimal digits of precision. If we want more (or fewer) we use the setprecision manipulator. Its use looks like this:

#include <iomanip>

...

cout << exp(1.) << endl; cout << setprecision(10); cout << exp(1.) << endl;

 

 

The output of this code looks like this:

 

 

 

 

 

2.71828

 

 

 

 

 

 

 

2.718281828

 

 

 

 

 

 

 

14.6.2 Showing all digits

Increasing the precision of the output stream does not necessarily result in additional digits being printed. For example, the statement

cout << setprecision(10) << 1.0 << endl;

just prints 1 on the screen. The manipulator showpoint coerces the printing of the decimal point and the extra digits. The code

cout << setprecision(10) << 1.0 << endl; cout << showpoint << 1.0 << endl;

results in the following output.

11.000000000

To restore the default behavior, send the noshowpoint object to the output stream.

310

C++ for Mathematicians

14.6.3 Setting the width

Setting the precision of the output does not directly determine the number of characters typed to the screen. A leading minus sign, the position of the first nonzero digit, whether the number is to appear in scientific notation, and whether showpoint is in effect all influence the number of characters that cout << x prints. This variability can wreak havoc with any attempt to line up the output in neat columns.

By default, cout << x; prints x in exactly as much space as required; no extra space is padded.

The setw manipulator provides a mechanism that guarantees the number of characters cout << x; prints. The statement

cout << setw(20) << x;

prints the value stored in x in a field that is 20 characters wide. If cout << x would normally produce fewer than 20 characters, then, by default, the value is printed right justified in the 20-character region. The code

cout << ’|’ << setw(20) << exp(1.) << ’|’ << endl;

results in this output.

 

2.71828|

|

It is possible for the printed value to appear left or right justified within the amount of space specified by setw. The manipulators controlling this are named left and right.

cout << ’|’ << setw(20) << left << exp(1.) << ’|’ << endl;cout << ’|’ << setw(20) << right << exp(1.) << ’|’ << endl;

 

|2.71828

|

 

|

2.71828|

 

 

Unlike the setprecision and showpoint manipulators, the effect of setw does not persist between outputs. Once output has been sent, the effect of setw is immediately canceled and the default behavior is restored. The code

cout << ’|’ << setw(20) << exp(1.) << ’|’ << M_PI << ’|’ << endl;

gives the following result.

 

 

 

 

 

 

2.71828|3.14159|

 

|

 

 

 

 

 

 

 

When using setw, the extra characters typed are spaces. However, this can be

 

 

changed with the setfill manipulator. Here is an example.

string hi("Hello Gauss"); cout << setfill(’-’);

cout << setw(20) << hi << endl;

cout << setw(20) << left << hi << endl;

---------Hello Gauss

Hello Gauss---------

Strings, Input/Output, and Visualization

311

14.6.4 Other manipulators

There are several additional manipulators available in C++; here we mention some of them that you might find useful.

cout << showpos: This causes nonnegative numbers to be prepended with a + sign. To restore the default behavior, use noshowpos.

cout << scientific: This forces real numbers (types float and double) to appear in scientific notation. To restore default behavior (real values are either printed in decimal or scientific notation depending on their value) use the statement cout << setiosflags(ios::floatfield);.

The mantissa of the real value is separated from the power of 10 by the letter e. The case of the letter e can be modified using the manipulators uppercase and nouppercase.

cout << fixed: This forces real numbers to be printed in decimal notation (and not scientific). For example:

 

 

cout << exp(20.0) << endl;

 

 

 

 

 

cout

<< fixed;

 

 

 

 

 

cout

<< exp(20.0) << endl;

 

 

 

 

 

4.85165e+08

 

 

 

 

 

 

 

485165195.409790

 

 

 

 

 

 

 

Restore default behavior with cout<<setiosflags(ios::floatfield);.

cout << boolalpha: By default, bool values are printed as 0 or 1. After applying the boolalpha manipulator, these are printed as false and true. Restore the default behavior with cout << noboolalpha;.

cout << dec, cout << oct, and cout << hex: Integer values are normally printed in base ten, but may also be printed in base eight (octal) or sixteen (hexadecimal). Use these manipulators to select the desired base.

14.7A class to parse files

We close this chapter by presenting a class for parsing files. In applied work, mathematicians often are given files containing data. It can be an annoying chore simply to read the file into a program. For example, a file might contain geometric information about a large molecule. The input file specifies the molecule with various kinds of lines:

312

C++ for Mathematicians

Type and location of atoms: These lines have the following format:

ATOM atom number symbol x-coord y-coord z-coord

Chemical bonds: These lines have the format:

BOND atom number atom number

Comments: These lines begin with a # and are followed by arbitrary text.

Blank lines.

Such an input file might look like this:

#Data acquired from the ACME Molecule Machine and

#saved in directory /shared/molecules/specimen-4.

ATOM 1

C

0

0

0

ATOM 2

H

1

0

0

ATOM

3

Br

0

-1 0

ATOM

4

C

0

0

1.2

#Here are the bonds

BOND 1 2

BOND 1 4

BOND 1 4

# Note double bond between the carbons BOND 1 3

The LineParser class we present in this section is a device that reads a file (such as the molecule description file above) one line at a time, and then breaks the line into individual words. The class provides the following methods.

The constructor LineParser(file_name): This creates a new LineParser object that reads data from the file named in the char* array file_name.

A method read() that reads a line from the input file and breaks it into individual words. This method returns true if it is able to read a line. Let’s call the last line processed by read() the current line.

A method show_line() that returns the current line.

A method show_line_number() that gives the line number of the current line.

A method num_words() that reports the number of separate words found on the current line.

A square brackets operator to get the words on the line. If LP is a LineParser object, LP[k] returns the kth word of the current line.

Here are the header and program files for the LineParser class followed by a main program that illustrates the use of this class.

Strings, Input/Output, and Visualization

313

Program 14.8: Header file for the LineParser class.

1 #ifndef LINE_PARSER_H

2 #define LINE_PARSER_H

3 #include <fstream>

4 #include <vector>

5#include <string>

6using namespace std;

7

8 class LineParser {

9private:

10

ifstream

in;

11

string

theLine;

12

long

lineNumber;

13

int

nWords;

14

vector<string>

words;

15

void

parse();

16

 

 

17public:

18LineParser(const char* file_name);

19bool read();

20string show_line() const { return theLine; }

21

long

show_line_number() const {

return lineNumber; }

22

int

num_words() const { return

nWords; }

23string operator[](int k) const { return words[k]; }

24};

25

26 #endif

Program 14.9: Program file for the LineParser class.

1 #include "LineParser.h"

2 #include <sstream>

3 #include <iostream>

4using namespace std;

5

6LineParser::LineParser(const char* file_name) {

7 in.open(file_name);

8if (!in) {

9cerr << "WARNING: Unable to open " << file_name << endl;

10}

11lineNumber = 0;

12theLine = "";

13}

14

15bool LineParser::read() {

16getline(in,theLine);

17bool result = in.good(); // check if getline succeeded

18if (result) {

19lineNumber++;

20parse();

21}

22return result;

23}

314

C++ for Mathematicians

24

25void LineParser::parse() {

26words.clear();

27words.resize(100);

28istringstream s(theLine);

29nWords = 0;

30string tmp;

31while (s>>tmp) {

32if (words.size() < unsigned(nWords)) words.resize(nWords+10);

33words[nWords] = tmp;

34nWords++;

35}

36}

Program 14.10: A program to demonstrate the use of the LineParser class.

1 #include "LineParser.h"

2 #include <iostream>

3using namespace std;

4

5int main(int argc, char** argv) {

6

7if (argc != 2) {

8 cerr << "Usage: " << argv[0] << " filename" << endl;

9return 1;

10

}

11

 

12

LineParser LP(argv[1]);

13

 

14while (LP.read()) {

15cout << "Line " << LP.show_line_number() << "\t\t\""

16<< LP.show_line() << "\"" << endl << endl;

17for (int k=0; k<LP.num_words(); k++) {

18cout << "Word " << k << " is \t\"" << LP[k] << "\"" << endl;

19}

20cout << "-------------------------------------------------"

21<< endl;

22}

23

24return 0;

25}

When the main program is run on the following four-line file

What’s it all about,

Alfie?

Catch 22

 

Nothing on the previous line!

we obtain the following output:

Line 1

 

"What’s it all about,

Alfie?"

Word

0

is

"What’s"

 

Word

1

is

"it"

 

 

 

Strings, Input/Output, and Visualization

315

 

 

 

Word 2 is

"all"

 

 

 

 

 

 

 

 

 

 

Word 3 is

"about,"

 

 

 

 

 

Word 4 is

"Alfie?"

 

 

 

 

-------------------------------------------------

 

 

 

 

Line 2

"Catch 22

"

 

 

 

 

Word 0 is

"Catch"

 

 

 

 

 

Word 1 is

"22"

 

 

 

 

-------------------------------------------------

 

 

 

 

Line 3

""

 

 

 

 

-------------------------------------------------

 

 

 

 

Line 4

"Nothing on the previous line!"

 

 

 

 

Word 0 is

"Nothing"

 

 

 

 

 

Word 1 is

"on"

 

 

 

 

 

Word 2 is

"the"

 

 

 

 

 

Word 3 is

"previous"

 

 

 

 

 

Word 4 is

"line!"

 

 

 

 

 

 

 

 

 

-------------------------------------------------

 

 

 

14.8Visualization

The visualization of mathematical objects often provides important insights. Computers are particularly adept at producing precise beautiful images.

Unfortunately, drawing pictures on the computer’s screen is often closely tied to the computer’s operating system; such a program created for the Windows operating system is unlikely to work on an X-windows (UNIX) or Macintosh computer. In addition, it can be frustrating and time consuming to understand the intricacies of opening windows, drawing graphic objects, translating between mathematical coordinates and screen coordinates, printing, and so forth.

Still, visualization is too important to dismiss and so we offer guidance on how to use C++ to draw pictures in a platform-independent manner.

One strategy, which we consider only briefly, is to write a C++ program whose textual output is used as input to another system with built-in graphics capabilities. For example, the C++ program could write a file in which each line contains a pair of real values. This file would then be loaded into a system such as MATLAB or

Mathematica and plotted.

Alternatively—and this is the technique we explore—we can write a C++ program whose output is a well-established graphics file such as GIF, JPEG, or EPS. This file can then either be displayed on the computer’s screen (using an appropriate viewing program) or incorporated into a word-processing document (such as MS Word or LATEX).