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

C++ For Mathematicians (2006) [eng]

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

286

C++ for Mathematicians

 

 

 

 

 

 

 

1050.000000 -18900.000000 79380.000000 -117600.000000 56700.000000

 

 

 

-1400.000000 26880.000000 -117600.000000 179200.000000 -88200.000000

 

 

 

630.000000 -12600.000000 56700.000000 -88200.000000 44100.000000

 

 

 

The eigenvalues of the Hilbert matrix are

 

 

 

0.000003

 

 

 

 

0.000306

 

 

 

 

0.011407

 

 

 

 

0.208534

 

 

 

 

1.567051

 

 

 

 

Trace calculated two ways: 1.7873 and 1.7873

 

 

 

 

13.3Other packages

There are many more packages available on the Web than we can possibly describe in detail. We conclude this chapter by listing a few additional packages that might be of interest. A well-chosen selection of keywords typed in a search engine is likely to turn up additional options.

Seldon is a full-feature linear algebra package, available for free online here: http://www.osl.iu.edu/research/mtl/

The Matrix Template Library is another package for working with matrices. Visit the Web site for more information and a free download:

http://www.osl.iu.edu/research/mtl/

The Computational Geometry Algorithms Library or CGAL for short is a large library of C++ classes and procedures for geometry work. Use it to find everything from convex hulls to Voronoi diagrams to minimum enclosing ellipses.

CGAL is available for free from www.cgal.org.

For graph theory work, try Boost, available for free from www.boost.org.

Read the installation instructions carefully. The first step is to build a helper program called bjam that is used to direct the building of boost itself.

For computational number theory, consider LiDIA. Based on the GMP package (see Section 13.1), it gives programmers the ability to do calculations in finite fields and on elliptic curves, use lattice reduction algorithms, perform linear algebra calculations, and more. It is available for free:

http://www.informatik.tu-darmstadt.de/TI/LiDIA/

Using Other Packages

287

The Library of Efficient Data Structures and Algorithms, also known as LEDA, is a commercial package for work in graph theory, geometry, cryptography, and more. More information, including pricing, is available here:

http://www.algorithmic-solutions.com/enleda.htm

Interested in computing the homology group (over Z or Zp) of a chain complex? Consider the C++ software available from CHomP—the Computational Homology Program. See their Web site for more information and a free download:

http://www.math.gatech.edu/˜chom/

13.4Exercises

13.1The base ten representation of 100! ends with a long string of zeros; it is a classic problem to find how many. Solve this problem with C++ using the GMP package.

13.2Write a program that fills a two-dimensional array with Pascal’s triangle. That is, the n,k-entry is nk . [If n < k, set nk = 0.] Build the table to include

rows/columns 0 through 20. Generate each row from the previous row using

n

n 1

n

k

1

.

the identity k =

k−1

+

 

What modification to your program would be necessary were you to increase the size of the table to 100 ×100?

Chapter 14

Strings, Input/Output, and Visualization

For the most part, mathematical work does not involve manipulation of character data. Nonetheless, it is useful to have a general understanding of how C++ handles character data, how to convert text to numbers, how to use command line arguments, and how to read and write data in files. We also show how to modify the formatting of output (e.g., how to increase the number of digits printed after the decimal point). We illustrate many of these ideas by creating a class to parse files one line at a time, and break those lines into individual words.

C++ has two ways to handle character data: arrays of char values and in objects of type string. The char arrays are a legacy of C++’s roots in the C programming language. It is necessary to understand their basics, but their use should be avoided where possible. The newer string variables are easier to use. We begin with a brief introduction to char arrays.

Textual and numerical output are important, but there are times when graphical output is especially insightful. We close this chapter with a discussion of how to draw pictures in C++.

14.1Character arrays

Character (or text) data consist either of individual characters (letters, numerals, punctuation) or of lists of characters. The C++ data type char holds a single character from the Latin character set (26 lowerand uppercase letters, numerals, white space, punctuation). These are known as the ASCII characters and are the only characters with which this book deals. Computers can also deal with a richer set of glyphs (from accented Latin letters to Chinese characters) using a system called unicode; this system is beyond our scope.

An ordered list of characters is generally called a character string. For example, the words Hello Gauss are such a list comprising 11 characters. As mentioned, C++ has two principal ways to work with character strings: as null-terminated char arrays and as objects of the class string. The character array representation is a primitive scheme inherited from the language C. It is useful for writing messages to the screen and other simple chores. The moment one wishes to do any manipulation of characters (e.g., concatenate two strings), the C++ string class makes program-

289

290

C++ for Mathematicians

ming much easier. We begin by discussing the basics of character arrays and then introduce the string class in the next section.

In a statement such as cout<<"The answer is "<<x<<endl;, the characters enclosed in quotation marks form a character array. That is, the sequence of letters is a C++ object of type char*: an array whose elements are type char.

In this book we have used character arrays exclusively for writing messages to the computer’s screen, but it is possible to hold such arrays in variables. For example:

const char* word = "Hello";

This creates an array of characters named word. The individual characters can be accessed using the usual array notation. For example, word[0] is the first character of the array, that is, H.

It is surprising to learn that the length1 of the array word (as declared above) is six (even though Hello is a five-letter word). Character arrays in C++ are null terminated; this means that after the last character of the string, the numerical value 0 is appended to mark the end of the string. Figure 14.1 illustrates how the contents of the variable word are stored inside the computer’s memory. The array is held at some

word

20320 20321 20322 20323 20324 20325

72

101

108

108

111

0

 

 

 

 

 

 

H e l l o

Figure 14.1: Illustrating a null-terminated character array.

location in memory (arbitrarily set at 20320 in the figure); the variable word holds that memory location. The elements of the array, word[0] through word[5], are stored as ASCII values. The letter H has ASCII value 72, hence that’s what is stored in word[0]. The subsequent values are 101, 108, 108, and 111 corresponding to the letters e, l, l, and o. Finally, word[5] contains the numerical value 0 (which does not correspond to any printable character) and this marks the end of the character array.

There are procedures for processing character array data; here are a few examples.

strlen gives the length of the character string (not including the terminating 0).

1The length of the character string is 5, but the length of the array that supports that string is 6. The C/C++ procedure strlen applied to the character array "Hello" returns the value 5.

Strings, Input/Output, and Visualization

291

strcpy and strncpy are used for copying one character array to another.

strcat and strncat are used to concatenate two character arrays; that is, if s1 is "Good" and s2 is "Morning", their concatenation is "GoodMorning".

strcmp and strncmp give a total ordering on the set of character arrays; this is useful for sorting a list of character strings or determining if two strings are equal.

On some compilers, you may need the directive #include <cstring> in order to use these procedures.

Using character arrays and their associated procedures is awkward and error prone. In nearly all cases, it is much simpler to use the C++ string class instead. So, rather than delve into the details of these procedures, we turn to the friendlier and more powerful string class.

14.2The string class

For any character processing tasks beyond the most basic, use C++’s string class. To use string objects, you might need the directive #include <string> (the header is optional with some compilers).

The string class contains a large number of features; in this section we discuss those with the greatest utility in mathematical work.

14.2.1 Initialization

Variables of type string can be declared in several ways; here are the most basic versions:

string s; declares s to be an empty character string.

string s("Hello"); declares s to be a character string containing the letters Hello. In lieu of "Hello" we can use any null-terminated character array, such as this:

const char* word = "Gauss"; string s(word);

Please note: It is not permissible to use a single char value as an argument to a string constructor. Thus, string s(’j’); is illegal. Instead, use string s("j");. Alternatively, the following is permissible.

string s;

s = ’j’; // this is OK

292

C++ for Mathematicians

string s(s2); initializes s with a copy of the string s2.

string s(s2,idx); initializes s with a copy of the portion of string s2 that starts at position idx.

string s(s2,idx,len); initializes s with a copy of the portion of string s2 that starts at position idx and runs for len characters. For example,

string s("Mathematics"); string t(s,2,3);

cout << t << endl;

writes the word the on the computer’s screen. Note that the 0th character of s is M.

string s(reps, ch); where ch is a character and reps is a nonnegative integer. This initializes s with reps copies of the character ch. For example,

string snore(10,’z’); cout << z << endl;

writes zzzzzzzzzz on the screen.

In addition to setting a string’s value when it is declared, we may modify its value using an assignment statement such as any of these:

s = "Gauss"; s = ’g’;

s = other; // other is another string object

14.2.2 Fundamental operations

The most basic operation one can perform on string objects is concatenation; the result of concatenating strings s1 and s2 is a new string comprising the characters of s1 immediately followed by the characters in s2. Concatenation of strings in C++ is denoted by the addition operator, +. For example, consider this code:

string s1("Hello "); string s2("Gauss"); cout << s1+s2 << endl;

This prints Hello Gauss on the computer’s screen. The + operation can be used to combine strings with single characters or with character arrays. Here are some examples.

string s("Hello");

cout << s + " Gauss" << endl; // writes "Hello Gauss"

string s1 = "good"; string s2 = "luck";

cout << s1 + ’ ’ + s2 << endl; // writes "good luck"

One string can be appended to the end of another using the += operation:

Strings, Input/Output, and Visualization

293

string s("Carl Friedrich");

s += ’ ’; // append a space

s += "Gauss"; // append the last name cout << s << endl;

writes Carl Friedrich Gauss on the screen.

Characters may be inserted into the middle of a string using the insert method. The statement s.insert(pos,t); inserts the string t into s just before character s[pos]. The statement s.insert(0,t); inserts the characters at the beginning of s. Here is an example.

string s("CarlGauss"); s.insert(4," Friedrich "); cout << s << endl;

writes Carl Friedrich Gauss on the screen.

In the statement s.insert(pos,t); the variable t may be either a string or a character array. It may not be type char.

s.insert(3,"x"); // allowed s.insert(3,’x’); // forbidden

The erase method is used for deleting characters from a string. The statement s.erase(pos); deletes all characters from position pos to the end of the string. For example,

string s = "abcdefghijklmnopqrstuvwxyz"; s.erase(5);

cout << s << endl;

writes abcde to the screen. (Remember, for the original string, s[5] is f.)

The statement s.erase(pos,nchars); deletes nchars of s starting at s[pos]. For example,

string s = "abcdefghijklmnopqrstuvwxyz"; s.erase(5,3);

cout << s << endl;

writes abcdeijklmnopqrstuvwxyz to the screen.

A portion of a string can be modified using the replace method. The statement s.replace(pos,nchars,new_chars); deletes nchars starting at position pos, and then inserts new_chars in place of the missing portion. The new_chars may be either a string or a char* character array, and may be of any length. Here is an example:

string s = "abcdefghijklmnopqrstuvwxyz"; s.replace(5,16,"...");

cout << s << endl;

This writes abcde...vwxyz to the screen.

294

C++ for Mathematicians

The substr method is used to extract a substring of a string; it does not modify the string. The expression s.substr(pos) returns the substring of s starting with character s[pos] through to the end of s. More generally, the expression s.substr(pos,nchars) returns the substring of s starting with s[pos] up to, but not including, s[pos+nchars]. Here is an example.

string s = "abcdefghijklmnopqrstuvwxyz"; cout << s.substr(5,3) << endl;

This writes fgh to the screen.

The length of a string can be ascertained using either s.size() or s.length(). One can test if the string is an empty string with s.empty() which returns true if the length of s is zero.

Square brackets can be used to access a given character in a string (either for reading or for modification). In consonance with C++ principles, s[0] is the first character of s. This code

string s = "good luck"; s[2] = ’l’;

cout << s << endl;

writes gold luck on the screen. The value between the square brackets must be nonnegative and less than the length of the string. Alternatively, the at method may be used: s.at(k) gives character number k of the string s (i.e., s[k]).

Two string objects may be compared using the standard C++ comparison operations: ==, !=, <, <=, >, and >=. The ordering is mostly lexicographic. However, all uppercase letters precede lowercase letters. The following program illustrates the ordering of string values; note that sort implicitly relies on the < operator.

Program 14.1: A program to illustrate the sorting of string values.

1 #include <iostream>

2using namespace std;

3

4const int NWORDS = 7;

5

6int main() {

7 string words[NWORDS];

8words[0] = " zebra";

9 words[1] = "ant eater";

10words[2] = "Aaron";

11words[3] = "aardvark";

12words[4] = "Baltimore";

13words[5] = "anteater";

14words[6] = "BREAKFAST";

15

16 sort(words, words+NWORDS);

17

18for (int k=0; k<NWORDS; k++) {

19cout << words[k] << endl;

20}

Strings, Input/Output, and Visualization

21

22return 0;

23}

Here is the output of this program.

zebra Aaron BREAKFAST Baltimore aardvark ant eateranteater

295

In a dictionary, aardvark precedes Aaron, but C++ sorts these the other way around because uppercase A comes before all lowercase letters. The space character precedes all letters, hence zebra is first in the sorted output.

14.2.3 Searching

The string class provides methods for searching for substrings. The most basic of these is find. The method is invoked with an expression such as s.find(pat) where s is a string and pat is a string or a char*. It returns the location of the first occurrence of pat in s. The following code prints the number 8 on the screen.

string s = "abcdefghijklmnopqrstuvwxyz"; cout << s.find("ijk") << endl;

What happens if find cannot find pat? The answer is complicated. To begin, we need to explain that find returns a value of type std::string::size_type. (If you include the statement using namespace std; then you may drop the prefix std::.) In most cases, we save the value returned by find in a variable for further processing. To do this, we use code such as this:

string s = "I feel like a louse"; string pat = "eel";

string::size_type idx; // or std::string::size_type idx; idx = s.find(pat);

In this case, idx is set equal to 3.

If, however, pat is set to "house", then find returns a special value named std::string::npos. (The prefix std:: may be omitted if we have the statement using namespace std;.) Here is a short program that illustrates how to use find.

#include <iostream> using namespace std;

int main() {

string s = "Mississippi"; string pat;

cout << "Enter substring --> "; cin >> pat;