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

C++ For Mathematicians (2006) [eng]

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

446

C++ for Mathematicians

8.8The 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.9The solution is to use iterators that point to the first and one-past-the-last elements 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

 

 

73 658

930 272 544

878 923

709

 

 

 

 

807 249

 

 

73 249

272 544

658 709 807

878 923

930

 

 

 

 

 

 

 

 

 

8.10This 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.11It 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 becomes 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.2Here 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.5See 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.1The 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; }

};

Answers

455

#endif

10.2 Here is a file parallelogram.h that defines all three classes.

#ifndef PARALLELOGRAM_H #define PARALLELOGRAM_H #include <cmath>

class Parallelogram { protected:

double a,b,c; public:

Parallelogram() { a = b = c = 0.; } Parallelogram(double x1, double x2, double y2) {

if (x1 < 0) x1 = -x1; if (y2 < 0) y2 = -y2; a = x1;

b = x2; c = y2;

}

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

return 2*sqrt(b*b + c*c) + 2*a;

}

};

class Rectangle : public Parallelogram { public:

Rectangle(double height, double width) : Parallelogram(width, 0., height) {}

double perimeter() const { return 2*a + 2*c; }

};

class Rhombus : public Parallelogram { public:

Rhombus(double x, double y) : Parallelogram(sqrt(x*x)+sqrt(y*y), x, y) {}

double perimeter() const { return 4*a; }

};

#endif

10.3 The class mycomplex can be defined in a header file, mycomplex.h, like this.

#ifndef MY_COMPLEX_H #define MY_COMPLEX_H

#include <complex> using namespace std;

class mycomplex : public complex<double> { public:

mycomplex() : complex<double> (0.,0.) {} mycomplex(double r) : complex<double> (r,0.) {} mycomplex(double r, double i) : complex<double> (r,i) {}