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

Tiêu đề C++ for Mathematicians
Trường học University of Mathematics
Chuyên ngành Computer Science
Thể loại Giáo trình
Thành phố Hanoi
Định dạng
Số trang 52
Dung lượng 0,96 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

The vector can either be the return value of the procedure or a reference argument: vector array2vectorconst long* list, long nels; void array2vectorconst long* list, long nels, vector&

Trang 1

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;

Trang 2

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];

Trang 3

 

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:

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.

Trang 4

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);

Trang 7

the current time of day.

9.3 Here is the header file EuclideanVector.h

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;

};

Trang 8

EuclideanVector operator*(double s, const EuclideanVector& v);ostream& operator<<(ostream& os, const EuclideanVector& v);

cerr << "Cannot construct vector with negative dimension"

<< endl << "using zero instead" << endl;

cerr << "Cannot set default dimension to be negative"

<< endl << "using zero instead" << endl;

Trang 9

for (int k=0; k<dim; k++) {

ans.coords[k] = coords[k] + that.coords[k];

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;

Trang 10

double value() const { return sqrt(n); }

S operator*(const S& that) const { return S(n + that.n); }};

ostream& operator<<(ostream& os, const S& s);

10.1 The two classes are defined in the following h file There is no need for a cc file.

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); }

Trang 11

double area() const { return c*a; }

double perimeter() const {

Trang 12

bool operator<(const mycomplex& that) const {

if (real() < that.real()) return true;

if (real() > that.real()) return false;

if (imag() < that.imag()) return true;

Next the operator < is defined Note that we use the complex<double> ods real() and imag() to access the data, and then use lexicographic order- ing.

meth-Here is a short main to test the mycomplex class.

Trang 13

The operator+ in Point uses the Segment(Point,Point) constructor

to convert a pair of points into a line segment We cannot put the code for operator+ inline in the declaration of the Point class because the required Segment(double,double) constructor has not yet been declared So we are compelled to write the code for operator+ in a separate cc file Here are the files pointseg.h and pointseg.cc

double getX() const { return x; }

double getY() const { return y; }

Segment operator+(const Point& that) const;

Point getA() const { return A; }

Point getB() const { return B; }

Point midpoint() const;

};

ostream& operator<<(ostream& os, const Point& P);

ostream& operator<<(ostream& os, const Segment& S);

#endif

#include "pointseg.h"

Segment Point::operator+(const Point& that) const {

return Segment(*this, that);

}

Point Segment::midpoint() const {

double x = (A.getX() + B.getX()) / 2;

double y = (A.getY() + B.getY()) / 2;

return Point(x,y);

Trang 14

Examine this header file and the problem should become clear.

In file included from alphabeta.cc:1:

alphabeta.h:5: error: field ‘b’ has incomplete type

10.6 The key idea is to derive Complexx as a subclass of complex<double> and add two Boolean data fields to signal whether the object is infinite and whether the object is invalid To save some typing, we typedef the symbol C to be shorthand for complex<double>

To define the arithmetic operators, we rely on the corresponding operators from complex To convert an object z of type Complexx to its parent class C ,

we use the expression C(z) So, to multiple Complexx objects w and z , we first check for special cases where either is infinite or invalid, and then to get the required product we may use the expression C(w)*C(z)

Here are the files Complexx.h and Complexx.cc To make this class more useful, we should add the operators += , -= , *= , and /= We should also extend all the arithmetic operators so that one of the arguments can be a double

#include <complex>

using namespace std;

Trang 15

bool isZero() const {

return !invalid && !infinite && C(*this) == C(0);

}

bool isInfinite() const {

return !invalid && infinite;

}

bool isInvalid() const { return invalid; }

bool operator==(const Complexx& that) const {

if (invalid || that.invalid) return false;

if (infinite && that.infinite) return true;

return C(*this) == C(that);

}

bool operator!=(const Complexx& that) const {

if (invalid || that.invalid) return false;

return !(*this == that);

}

Complexx operator+(const Complexx& that) const;

Complexx operator-() const;

Complexx operator-(const Complexx& that) const;

Complexx operator*(const Complexx& that) const;

Complexx operator/(const Complexx& that) const;

Trang 17

11.1 Here is a hint Suppose that π is written in disjoint cycle notation The order

of π is the least common multiple of lengths of the cycles Also for positive

integers a and b, the least common multiple of a and b is ab /gcd(a,b).

11.2 Here is the file Counted.h Notice how we use the constructor just to ment the variable n_objects and the destructor to decrement it.

Trang 18

This header file contains nearly everything except the code to initialize the static class variable n_objects This is done in a separate source file, Counted.cc :

parts = new int[n_parts+1];

for (int k=0; k<n_parts; k++) parts[k] = that.parts[k];}

parts = new int[n_parts+1];

for (int k=0; k<n_parts; k++) parts[k] = that.parts[k];return *this;

}

void add_part(int n);

int get_sum() const { return sum; }

int nparts() const { return n_parts; }

int operator[](int k) const;

bool operator<(const Partition& that) const;

Trang 19

int* new_parts = new int[n_parts+1];

for (int k=0; k<n_parts; k++) {

bool Partition::operator<(const Partition& that) const {

if (sum < that.sum) return true;

if (sum > that.sum) return false;

if (n_parts < that.n_parts) return true;

if (n_parts > that.n_parts) return false;

for (int k=0; k<n_parts; k++) {

if (parts[k] < that.parts[k]) return true;

if (parts[k] > that.parts[k]) return false;

Trang 20

˜SmartArray() { delete[] data; }

long get_N() const { return N; }

simply return a copy of the value held in slot kk of the data This is just like call by value, but in this case, it’s return by value.

By declaring the return type to be long& , we switch from returning a copy of

a value to returning the actual item itself; that is, we have implemented return

is, effectively, transformed into X.data[9] = 4;

Trang 21

11.6 The following code is a file named LFT.h that defines the class LFT tice that we defined C to be an abbreviation for complex<double> We include get methods to extract the coefficients of the transformation and an operator<< to print the transformations to the screen.

C getA() const { return a; }

C getB() const { return b; }

C getC() const { return c; }

C getD() const { return d; }

11.7 The files 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

Trang 22

single-argument constructor) However, a separate Point+Path procedure is necessary.

long size() const { return npts; }

Path operator+(const Path& that) const;

Point operator[](int k) const;

};

Path operator+(const Point& X, const Path& P);

ostream& operator<<(ostream& os, const Path& P);

for (int k=0; k<npts; k++) ans.pts[k] = pts[k];

for (int k=0; k<that.npts; k++) ans.pts[k+npts] = that.pts[k];return ans;

Trang 23

copy_array = new T[nels];

for (int k=0; k<nels; k++) copy_array[k] = array[k];

n/2 of (the sorted copy of) an array with n elements.

12.2 Here is the new version of SmartArray.h

Trang 24

N = (nels > 1) ? nels : 1;

data = new T[N];

}

˜SmartArray() { delete[] data; }

long get_N() const { return N; }

12.5 Here is a file triple.h that defines the triple class and the make_triple procedure templates.

Trang 25

first = x; second = y; third = z;

}

bool operator<(const triple& that) const {

if (first < that.first) return true;

if (first > that.first) return false;

if (second < that.second) return true;

if (second > that.second) return false;

if (third < that third) return true;

return false;

}

};

template <class A, class B, class C>

triple<A,B,C> make_triple(const A& x, const B& y, const C& z) {return triple<A,B,C>(x,y,z);

#include <iostream>

using namespace std;

int LIMIT = 8*sizeof(unsigned long);

void print_set(unsigned long x) {

cout << "{ ";

for (int k=0; k<LIMIT; k++) {

unsigned long mask = 1<<k;

Trang 26

unsigned long top = (1<<n) - 1;

for (unsigned long x = 0 ; x <= top; x++) {

Trang 27

int main() {

int table[NROWS][NROWS];

table[0][0] = 1;

for (int k=1; k<NROWS; k++) table[0][k] = 0;

for (int n=1; n<NROWS; n++) {

for (int n=0; n<NROWS; n++) {

for (int k=0; k<NROWS; k++) {

To extend this to a 100 × 100 table, it is not enough to change the value of

NROWS The binomial coefficients grow too large to fit in long variables Even long long variables are not big enough (assuming that these are 64 bits) Instead, we need to use arbitrary precision integers (e.g., from the GMP package) or settle for decimal approximations (i.e., use a double table) 14.1 Here are two solutions First, we can convert the string into a char* array, and then use atoi :

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

Trang 28

reduce are used to cancel adjacent inverse elements The clear_check method is used by the constructor to prevent the inclusion of improper charac- ters.

string toString() const { return word; }

Free operator*(const Free& that) const {

Trang 30

for (char ch=’a’; ch <= ’z’; ch++) {

int idx = ch - ’a’;

14.6 A complete program to count polygrams in a text file is included on the companying CD-ROM.

ac-14.7 The following program uses the Point class from Chapter 6 (files Point.h and Point.cc ) plus the files Koch.h , Koch.cc , and main.cc that we present here.

Trang 31

Letter frequency chart to accompany solution to Exercise 14.5.

Letter Frequency (percent)

void koch_step(const Point& P, const Point& Q,

Point& X, Point& Y, Point& Z);

Trang 32

const double theta = M_PI/3;

void koch_step(const Point& P, const Point& Q,

Point& X, Point& Y, Point& Z) {double a = P.getX();

Trang 33

for (int k=0; k<K.size()-1; k++) {

When run at depth 5, the following image is produced.

14.8 Here is a program to draw the Mandelbrot set.

const int MAX_ITS = 500;

const int PIXELS = 1000;

const char* FILE_NAME = "mandelbrot.gif";

Trang 34

for (int i=0; i<PIXELS; i++) {

for (int j=0; j<PIXELS; j++) {

It produces the following image.

15.1 Here is Card.h with all methods and procedures inline.

const int ACE = 1;

const int JACK = 11;

const int QUEEN = 12;

Trang 35

const int KING = 13;

const string value_names[] = { "nil", "ace", "two", "three",

"four", "five", "six", "seven",

"eight", "nine", "ten",

"jack", "queen", "king" };

const string suit_names[] = { "clubs", "diamonds",

int card2int() const {

return 13*suit + value;

}

public:

Card() { value = ACE; suit = SPADES; }

Card(int spots, Suit family) {

bool operator<(const Card& that) const {

return card2int() < that.card2int();

}

bool operator==(const Card& that) const {

return card2int() == that.card2int();

}

bool operator!=(const Card& that) const {

return card2int() != that.card2int();

15.2 The statement T* xp = new T(10); creates a single new object of type T

in which the value 10 is supplied to the class T constructor.

The statement T* xp = new T[10]; creates a new array to hold 10 objects

of type T

15.3 Notice that in the following program we catch a bad_alloc that is thrown by

Trang 36

new when there is not enough memory to allocate (The prefix std:: is not necessary because we declared using namespace std; )

point-= a=b assignment, a==b equality testing, combined with < and > for ≤ and

≥, and combined with ! for inequality testing.

< a<b for less than, a<<b for bit shift and stream output, and used with > for declaring templates and for #include of standard headers See also =

> 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.

: class : public subclass inheritance, label: statement; ing, case 1: label in a switch statement,

label-Child(argument_list) : Parent(argument_sublist) { }

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

TỪ KHÓA LIÊN QUAN