1. Trang chủ
  2. » Công Nghệ Thông Tin

C++ for Mathematicians An Introduction for Students and Professionals phần 10 ppt

52 427 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 52
Dung lượng 0,96 MB

Nội dung

Answers 445 6 = 1+1+1+1+1+1 11 partitions of 6 ✝ ✆ 8.7 The solution is to use a static look-up table that takes pairs of long values as keys. To create such a table, be sure to #include <map> and give the following declaration. static map< pair<long,long> , long > table; Here is a program with a binomial procedure and a main to check that it works. #include <map> #include <iostream> using namespace std; long binomial(long n, long k) { static map< pair<long,long> , long > table; if (k>n) return 0; if (k==0) return 1; if (k==n) return 1; pair<long, long> args = make_pair(n,k); if (table.count(args) > 0) { return table[args]; } table[args] = binomial(n-1,k-1) + binomial(n-1,k); return table[args]; } int main() { for (int n=0; n<10; n++) { for (int k=0; k<10; k++) { cout << binomial(n,k) << "\t"; } cout << endl; } return 0; } The code gives Pascal’s triangle as output. ✞ ☎ 1000000000 1100000000 1210000000 1331000000 1464100000 151010510000 1615201561000 1 7 213535217 1 0 0 1 8 28567056288 1 0 1 9 368412612684369 1 ✝ ✆ 446 C++ for Mathematicians 8.8 The inputs to the procedure are the array and an integer specifying the length of the array. The vector can either be the return value of the procedure or a reference argument: vector<long> array2vector(const long * list, long nels); void array2vector(const long * list, long nels, vector<long>& vlist); The first is, perhaps, more natural, however, the second is more efficient. The problem with the first approach is that when the return statement executes, the vector<long> built in the procedure is copied to the receiving variable in the calling procedure. Here is code for the procedure using the second approach. #include <vector> using namespace std; void array2vector(const long * list, long nels, vector<long>& vlist) { vlist.resize(nels); for (int k=0; k<nels; k++) vlist[k] = list[k]; } 8.9 The solution is to use iterators that point to the first and one-past-the-last ele- ments of the vector like this, sort(values.begin(), values.end()); The following code illustrates this approach. #include <vector> #include <iostream> using namespace std; const int N = 10; int main() { vector<long> values; values.resize(N); for (int k=0; k<N; k++) { values[k] = rand()%1000; cout << values[k] << " "; } cout << endl << endl; sort(values.begin(), values.end()); for (int k=0; k<N; k++) cout << values[k] << " "; cout << endl; return 0; } Here is the output of this program. Answers 447 ✞ ☎ 807 249 73 658 930 272 544 878 923 709 73 249 272 544 658 709 807 878 923 930 ✝ ✆ 8.10 This is dangerous. The iterator is now focused on a part of a set that no longer exists. Such an action renders the iterator invalid. Even worse, all iterators referring to the modified set are now invalid. 8.11 It is tempting (but wrong) to write code like this: set<long>::iterator sp; for (sp = A.begin(); sp != A.end(); ++sp) { if ( * sp%2 == 1) A.erase( * sp); } The problem, as we discussed in the solution to Exercise 8.10, is that once we erase the element referred to by an iterator, the iterator beco mes invalid. We need a different approach. The technique we illustrate here is to step through the set and place a copy of the odd elements we find in a container (in the following code we use a stack, but other choices would work as well). Once we have accumulated copies of all the odd elements in the set, we run through the stack and delete the corresponding elements from the set. Here’s the code. #include <set> #include <stack> using namespace std; void delete_odds(set<long>& A) { stack<long> eliminate; set<long>::const_iterator sp; for (sp=A.begin(); sp!=A.end(); ++sp) { if ( * sp % 2 == 1) eliminate.push( * sp); } while (!eliminate.empty()) { A.erase(eliminate.top()); eliminate.pop(); } } 8.12 Here is the code. #include <set> #include <algorithm> #include <iostream> using namespace std; void print_element(long x) { cout << x << " "; } void print_set(set<long>& A) { cout << "{ "; for_each(A.begin(), A.end(), print_element); 448 C++ for Mathematicians cout << "}" << endl; } Note that we first define the procedure print_element. This procedure is used as an argument to for_each in the print_set procedure. 9.2 Here is a complete solution. First we present the header file Time.h in which the short methods are defined inline. The private method adjust() is used to correct the variables so they fall in the proper ranges. For example, if the hour/minute/second variables have values (5,59,65), then adjust would change these to (6,0,5). Notice the use of a static variable ampm_style that is modified via the static methods ampm() and military(). #ifndef TIME_H #define TIME_H #include <iostream> using namespace std; class Time { private: long hour, min, sec; static bool ampm_style; void adjust(); public: Time() { hour = min = sec = 0; } Time(int H, int M, int S); Time operator+(long n) const; Time operator-(long n) const; Time operator++(); Time operator (); int get_hour() const { return hour; } int get_minute() const { return min; } int get_second() const { return sec; } static void ampm() { ampm_style = true; } static void military() { ampm_style = false; } static bool is_ampm() { return ampm_style; } }; Time operator+(long n, const Time& T); ostream& operator<<(ostream& os, const Time& T); #endif Next we give the code file Time.cc. #include "Time.h" bool Time::ampm_style = true; void Time::adjust() { // adjust the seconds field first Answers 449 if (sec < 0) { long change = (-sec)/60 + 1; sec += change * 60; min -= change; } if (sec > 59) { long change = sec/60; sec -= change * 60; min += change; } // adjust the min field next if (min < 0) { long change = (-min)/60 + 1; min += change * 60; hour -= change; } if (min > 59) { long change = min/60; min -= change * 60; hour += change; } // finally, adjust the hour if (hour < 0) { long change = (-hour/24) + 1; hour += change * 24; } if (hour > 23) { hour %= 24; } } Time::Time(int H, int M, int S) { hour = H; min = M; sec = S; adjust(); } Time Time::operator+(long n) const { Time T = * this; T.sec += n; T.adjust(); return T; } Time operator+(long n, const Time& T) { return T+n; } Time Time::operator-(long n) const { Time T = * this; T.sec -= n; T.adjust(); return T; } 450 C++ for Mathematicians Time Time::operator++() { ++sec; adjust(); return * this; } Time Time::operator () { sec; adjust(); return * this; } ostream& operator<<(ostream& os, const Time& T) { long h = T.get_hour(); long m = T.get_minute(); long s = T.get_second(); if (Time::is_ampm()) { // am-pm style if (h==0) { os << 12; } else if (h>12) { os << h-12; } else { os << h; } os << ":"; if (m < 10) os << 0; os << m; os << ":"; if (s < 10) os << 0; os << s; if (h < 12) { os << " am"; } else { os << " pm"; } } else { // military time os << h << ":"; if (m < 10) os << 0; os << m << ":"; if (s < 10) os << 0; os << s ; } return os; } Finally, the following code shows how to extract the current local time on a UNIX computer. Unfortunately, it is difficult to understand. Fortunately, it is unusual for a program that solves a mathematics problem to need to deal with Answers 451 the current time of day. #include <ctime> #include <iostream> #include "Time.h" using namespace std; Time now() { time_t clock = time(0); long h = localtime(&clock)->tm_hour; long m = localtime(&clock)->tm_min; long s = localtime(&clock)->tm_sec; return Time(h,m,s); } int main() { cout << "At the tone, the time will be " << now() << endl; return 0; } If you need to deal extensively with date and time matters, it is worth your while to download, build, and install a package created by someone else. For example, the Boost C++ package provides classes for working with date and time. (See Chapter 13 about working with packages you find on the Web including a brief description of Boost on page 286.) 9.3 Here is the header file EuclideanVector.h. #ifndef EUCLIDEAN_VECTOR_H #define EUCLIDEAN_VECTOR_H #include <vector> #include <iostream> using namespace std; class EuclideanVector { private: static int DEFAULT_DIM; int dim; vector<double> coords; public: EuclideanVector(); EuclideanVector(int n); static int get_default_dim() { return DEFAULT_DIM; } static void set_default_dim(int n); double get(int n) const; void set(int n, double x); int get_dim() const { return dim; } EuclideanVector operator+(const EuclideanVector& that) const; EuclideanVector operator * (double s) const; bool operator==(const EuclideanVector& that) const; bool operator!=(const EuclideanVector& that) const; }; 452 C++ for Mathematicians EuclideanVector operator * (double s, const EuclideanVector& v); ostream& operator<<(ostream& os, const EuclideanVector& v); #endif Here is the code file EuclideanVector.cc. #include "EuclideanVector.h" int EuclideanVector::DEFAULT_DIM = 2; EuclideanVector::EuclideanVector() { dim = DEFAULT_DIM; coords.resize(dim); for (int k=0; k<dim; k++) coords[k] = 0.; } EuclideanVector::EuclideanVector(int n) { if (n < 0) { cerr << "Cannot construct vector with negative dimension" << endl << "using zero instead" << endl; n=0; } dim = n; coords.resize(n); for (int k=0; k<dim; k++) coords[k] = 0.; } void EuclideanVector::set_default_dim(int n) { if (n < 0) { cerr << "Cannot set default dimension to be negative" << endl << "using zero instead" << endl; n=0; } DEFAULT_DIM = n; } double EuclideanVector::get(int n) const { n %= dim; if (n < 0) n += dim; return coords[n]; } void EuclideanVector::set(int n, double x) { n%=dim; if (n < 0) n += dim; coords[n] = x; } EuclideanVector EuclideanVector::operator+(const EuclideanVector& that) const { if (dim != that.dim) { cerr << "Attempt to add vectors of different dimensions" << endl; return EuclideanVector(0); } EuclideanVector ans(dim); Answers 453 for (int k=0; k<dim; k++) { ans.coords[k] = coords[k] + that.coords[k]; } return ans; } EuclideanVector EuclideanVector::operator * (double s) const { EuclideanVector ans(dim); for (int k=0; k<dim; k++) ans.coords[k] = s * coords[k]; return ans; } bool EuclideanVector::operator==(const EuclideanVector& that) const { if (dim != that.dim) return false; for (int k=0; k<dim; k++) { if (coords[k] != that.coords[k]) return false; } return true; } bool EuclideanVector::operator!=(const EuclideanVector& that) const { return !( ( * this) == that ); } EuclideanVector operator * (double s, const EuclideanVector& v) { return v * s; } ostream& operator<<(ostream& os, const EuclideanVector& v) { os << "[ "; for (int k=0; k<v.get_dim(); k++) os << v.get(k) << " "; os << "]"; return os; } 9.4 Here are the files S.h and S.cc that implement the set S and its operation ∗. #ifndef S_H #define S_H #include <iostream> #include <cmath> using namespace std; class S { private: long n; public: S(){n=0;} S(long a) { if (a<0) a = -a; n=a; } long getN() const { return n; } 454 C++ for Mathematicians double value() const { return sqrt(n); } S operator * (const S& that) const { return S(n + that.n); } }; ostream& operator<<(ostream& os, const S& s); #endif #include "S.h" ostream& operator<<(ostream& os, const S& s) { os << "sqrt(" << s.getN() << ")"; return os; } 9.5 See the file quaternions.h on the CD-ROM that accompanies this book. This file includes embedded Doxygen comments and the CD-ROM includes the Web pages they generate. 10.1 The two classes are defined in the following .h file. There is no need for a .cc file. #ifndef _RECTANGLE_ #define _RECTANGLE_ class Rectangle { protected: double h,w; // hold the height and width public: Rectangle(double x=1.0, double y=1.0) { h=x; w=y; } double get_width() const { return w; } double get_height() const { return h; } void set_width(double x) { w = x; } void set_height(double y) { h = y; } double area() const { return h * w; } double perimeter() const { return 2. * (h+w); } }; class Square : public Rectangle { public: Square(double s = 1.) : Rectangle(s,s) { } void set_width(double x) { w = x; h = x; } void set_height(double y) { w = y; h = y; } }; [...]... less than, a a>b for greater than, a>>b for bit shift and stream input See also =, -, and > ! !a Boolean not See also = & a&b bitwise and, &a address of, type& var reference declaration, a&&b Boolean and | a|b bitwise or and a||b Boolean or ˜ ˜a bitwise not and ˜Class destructor... x and x decrement, and combined with > to give -> arrow operator * a*b multiplication, *x pointer/iterator dereferencing, type* var pointer/array declaration, and combined with / to delimit comments: /* and */ / a/b division and/ / single line comment See also * = a=b assignment, a==b equality testing, combined with < and > for ≤ and ≥, and combined with ! for inequality testing < a> operator: istringstream is(s); int n; is >> n; 14.2 ifstream fin(file_name.cstr()); 14.3 The addition of a char and an int results in an int, and so instead of writing the letters a through z, instead we see the ASCII values for these... { ans.infinite = true; return ans; } return ans; } Complexx Complexx::operator/(const Complexx& that) const { Complexx ans(C(*this) / C(that)); if (invalid || that.invalid) { ans.invalid = true; return ans; } if (isZero() && that.isZero()) { ans.invalid = true; return ans; Answers 461 } if (infinite && that.infinite) { ans.invalid = true; return ans; } if (infinite) { ans.infinite = true; return ans;... Path.h and Path.cc follow Note that we used a vector container to house the points This is easier than managing a Path* array As a bonus, because we do not need to delete[] any arrays we allocated, we do not need a ˜Path() destructor Also note that we did not define an operator+ for the case Path+Point The C++ compiler knows how to convert a Point to a Path (thanks to the 466 C++ for Mathematicians single-argument... The solution is to replace ’a’+k with char(’a’+k) 14.4 Here are the header and code files, Free.h and Free.cc, that implement the Free class Note that we include constructors for building Free objects from a single character, a string, and a char* array The helper methods named 472 C++ for Mathematicians reduce are used to cancel adjacent inverse elements The clear_check method is used by the constructor... (word.size() < 2) return; for (int k=0; k0) k; } } } Free Free::inverse() const { Free ans; ans.word = word; int n = int(word.size()); for (int k=0; k . output. ✞ ☎ 100 0000000 1100 000000 1 2100 00000 13 3100 0000 146 4100 000 1 5101 0 5100 00 16152015 6100 0 1 7 213535217 1 0 0 1 8 28567056288 1 0 1 9 368412612684369 1 ✝ ✆ 446 C++ for Mathematicians 8.8 The. date and time matters, it is worth your while to download, build, and install a package created by someone else. For example, the Boost C++ package provides classes for working with date and time { Complexx ans(C( * this) + C(that)); if (invalid || that.invalid) { ans.invalid = true; return ans; } if (infinite && that.infinite) { ans.invalid = true; 460 C++ for Mathematicians return ans; } if

Ngày đăng: 12/08/2014, 12:20

TỪ KHÓA LIÊN QUAN