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

C++ For Mathematicians (2006) [eng]

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

16

C++ for Mathematicians

28

29// Floating point types

30cout << "The size of float is " << sizeof(float)

31<< " bytes" << endl;

32cout << "The size of double is " << sizeof(double)

33<< " bytes" << endl;

34

35// long double might not exist on all computers

36cout << "The size of long double is " << sizeof(long double)

37<< " bytes" << endl;

38

 

 

 

39

 

return 0;

 

40

}

 

 

 

 

 

 

 

The output of this program depends on the computer on which it is run. The

 

 

following show the results of running this code on two different machines.

 

 

 

The

size

of

short is

2 bytes

 

 

The

size

of

int is 4

bytes

 

 

The

size

of

long is 4 bytes

 

 

The

size

of

long long is 8 bytes

 

 

The

size

of

char is 1 bytes

 

 

The

size

of

bool is 4 bytes

 

 

The

size

of

float is

4 bytes

 

 

The

size

of

double is 8 bytes

 

The

size

of

long double is 8 bytes

 

 

 

 

 

 

 

 

The

size

of

short is

2 bytes

 

 

 

The

size

of

int is 4

bytes

 

 

The

size

of

long is 4 bytes

 

 

The

size

of

long long is 8 bytes

 

 

The

size

of

char is 1 bytes

 

 

The

size

of

bool is 1 bytes

 

 

The

size

of

float is

4 bytes

 

 

The

size

of

double is 8 bytes

 

 

The size of long double is 12 bytes

 

Notice that an int is 4 bytes on both machines and so, in both cases, int variables

 

 

 

can hold values from −231 to 231 −1.

Note also that double variables on both machines are 8 bytes, but this does not tell us the range of values that double values can take.

For the float and double data types, there are three quantities of interest: the largest value, the smallest positive value, and the difference between 1 and the smallest value greater than 1. This latter value is known as the epsilon value of the data type. Knowing that a double is 8 bytes does not immediately reveal these three quantities.

C++ provides header files with this information. The header file climits gives the minimum and maximum value of various integer types. It defines symbols such as INT_MIN and INT_MAX that are equal to the smallest and largest value an int may hold. Similarly, the header file cfloat gives the minimum positive, maximum, and epsilon values for float, double, and long double (if available) data types.

Numbers

17

Running the following program reports all this information for the data types we have discussed.

Program 2.4: A program to show the maximum and minimum values of various data types.

1#include <iostream>

2

#include

<climits>

//

max

&

min

size

of

integer types

3

#include

<cfloat>

//

max

&

min

size

of

real types

4using namespace std;

5

6/**

7* Print out the extreme values of various integer types.

8 */

9

10int main() {

11cout << "The maximum size of a short is " << SHRT_MAX << endl;

12cout << "The minimum size of a short is " << SHRT_MIN << endl;

13

14cout << "The maximum size of an int is " << INT_MAX << endl;

15cout << "The minimum size of an int is " << INT_MIN << endl;

16

17cout << "The maximum size of a long is " << LONG_MAX << endl;

18cout << "The minimum size of a long is " << LONG_MIN << endl;

19

20// long long values might not exist on some computers

21cout << "The maximum size of a long long is " << LLONG_MAX << endl;

22cout << "The minimum size of a long long is " << LLONG_MIN << endl;

23

24

25cout << "The minimum positive value of a float is "

26<< FLT_MIN << endl;

27cout << "The minimum epsilon value of a float is "

28<< FLT_EPSILON << endl;

29cout << "The maximum value of a float is "

30<< FLT_MAX << endl;

31

32cout << "The minimum positive value of a double is "

33<< DBL_MIN<< endl;

34cout << "The minimum epsilon value of a double is "

35<< DBL_EPSILON << endl;

36cout << "The maximum value of a double is "

37<< DBL_MAX << endl;

38

39// long double might not be defined on some systems

40cout << "The minimum positive value of a long double is "

41<< LDBL_MIN<< endl;

42cout << "The minimum epsilon value of a long double is "

43<< LDBL_EPSILON << endl;

44cout << "The maximum value of a long double is "

45<< LDBL_MAX << endl;

46

47 return 0;

48 }

18

C++ for Mathematicians

 

 

 

 

 

 

Here is the output of this program on a particular computer. The result on other

 

 

 

 

 

computers may be different.

 

 

 

 

 

 

 

The maximum size of a short is 32767

 

 

 

 

 

 

 

The minimum size of a short is -32768

 

 

 

 

 

The maximum size of an int

is

2147483647

 

 

 

 

 

The minimum size of an int

is

-2147483648

 

 

 

 

 

The maximum size of a long

is

2147483647

 

 

 

 

 

The minimum size of a long

is -2147483648

 

 

 

 

 

The maximum size of a long

long is 9223372036854775807

 

 

 

 

 

The minimum size of a long

long is -9223372036854775808

 

 

 

 

 

The minimum positive value

of a float is 1.17549e-38

 

 

 

 

 

The minimum epsilon value of a float is 1.19209e-07

 

 

 

 

 

The maximum value of a float is 3.40282e+38

 

 

 

 

 

The minimum positive value

of a double is 2.22507e-308

 

 

 

 

 

The minimum epsilon value of a double is 2.22045e-16

 

 

 

 

 

The maximum value of a double is 1.79769e+308

 

 

 

 

 

The minimum positive value

of a long double is 2.22507e-308

 

 

 

 

 

The minimum epsilon value of a long double is 2.22045e-16

 

 

 

 

 

The maximum value of a long double is 1.79769e+308

 

 

 

 

 

 

 

2.5Standard operations

C++ provides the familiar arithmetic operations. The expressions x+y, x-y, x*y, and x/y are the usual sum, difference, product, and quotient of x and y.

In these expressions, x and y may be any of the numeric types we discussed. However, mixing types can sometimes cause problems and confusion. If x and y are of the same type, then the result of the operation is also that type. For example, consider the following code.

int

numerator

=

13;

int

denominator

=

5;

double

quotient;

 

 

quotient = numerator/denominator;

cout << quotient << endl;

We might expect this code to print the value 2.6 on the computer’s screen. The surprise is that the computer prints 2. To understand why, we have to remember that when two int values are divided, the result is an int. In this case, C++ divides the integers 13 and 5 to give the result 2 (the fractional part is lost) and then assigns that value to quotient. Because quotient is of type double there is a silent, behind-the-scenes conversion of the int quantity into a double quantity.

We can coerce C++ to give us the answer 2.6 by converting 13 or 5 (or both) into double variables. We replace quotient = numerator/denominator with this:

Numbers

19

quotient = double(numerator) / double(denominator);

The expression double(numerator) converts the integer value in numerator into a double quantity. This conversion process is known as casting. Note that the variables numerator and denominator are unaffected by this; they remain type int and their type cannot be changed. What double(numerator) does is create a temporary double number to be used in the division.

We do not have to cast both numerator and denominator to type double. Once we cast one of them to double, we have an expression involving a double and an int. In this case, C++ automatically converts the other value as well.

Algebraic expressions may contain explicit numbers in addition to variables, such as x = 2*x+3;. This expression means that we take the value of x, multiply that by 2, then add 3, and then save the result of the calculation back into x. So if the initial value of x is 10, after this statement x would hold the value 23.

Numbers written without a decimal point are assumed to be integers, and numbers with decimal points are assumed to be floating point values. Consider the following code.

cout << 13/5

<< endl;

cout << 13./5

<< endl;

cout <<

13./5. <<

endl;

cout <<

13/5.

<<

endl;

The first of these prints 2 and the other three print 2.6.

For integer variables, the percent sign denotes the mod operation. The expression 237 % 100 evaluates to 37.

Unfortunately, the % operation is not exactly the same as the mathematician’s mod. For us, when a and b are integers with b > 0, we have that a mod b is the remainder r in the division of a by b where r must satisfy 0 ≤ r < b. Even if a is negative, the result of a mod b is nonnegative. However, in C++, if a is negative and b is positive, a%b is negative. Furthermore, C++ allows b to be negative, or even zero! Use the following program to explore the result of a%b various choices of a and b.

Program 2.5: A program to explore C++’s mod operation.

1 #include <iostream>

2using namespace std;

3

4/**

5* A program to investigate the behavior of the mod (%) operation.

6 */

7

8 int main() {

9int a,b;

10

11cout << "Enter the first number --> ";

12cin >> a;

13

14cout << "Enter the second number --> ";

15cin >> b;

20

C++ for Mathematicians

16 17 cout << a << " % " << b << " = " << a%b << endl;

18

19return 0;

20}

Line 11 types the words Enter the first number --> onto the screen. Notice that we did not include an endl, so the computer does not move the cursor to a new line.

Line 12 introduces the cin object. The statement cin >> a means read a value from the computer’s keyboard and save the result in the variable a.

C++ provides an interesting combination of arithmetic operations and assignment. The statement x += 4; is an abbreviation for x = x+4;—increase the value held in x by 4. All of the usual arithmetic operations can be used in this combined syntax.

Statement

Meaning

x += y;

x = x+y;

x -= y;

x = x-y;

x *= y;

x = x*y;

x /= y;

x = x/y;

x %= y;

x = x%y;

In computer programs, one frequently wishes to increase or decrease an integer variable by 1; this happens when we want to consider successive elements of an array or when counting. A special syntax can be used in place of x += 1 and x -= 1. The expressions x++ and ++x both increase x by one, and x-- and --x both decrease x by one. We call ++ and -- the increment and decrement operators, respectively.

The expressions x++ and ++x are not exactly the same. We explain the difference here because you might need to understand someone else’s program that relies on this difference. You should not take advantage of the difference between ++x and x++. Doing so makes your code more confusing, and the most likely victim of that confusion will be you. So read the next portion if you are curious, or you can safely skip ahead (past the material enclosed between the double lines) to the discussion on exponentiation.

With that admonishment firmly in place, here is the difference between x++ and ++x. Although both of these expressions increase the value of x by one, the result of this expression is, in the first case the old value of x and in the latter case, the new value of x. For example, consider this code.

int x,y; x = 10; y = x++;

cout << y << endl;

int a,b; a = 10; b = ++a;

cout << b << endl;

Numbers

21

The statement y = x++; assigns the old value of x to y, so cout << y << endl; types 10 on the console. On the other hand, the statement b = ++a; assigns the new value of a to b, so the statement cout << b << endl; types 11 on the console.

The two versions of ++ are called preincrement (for ++x) and postincrement (for x++). Similarly, the two versions of -- are called predecrement and postdecrement. And, as you might suspect, the name of the language is inspired by the ++ operator as C++ is an extension of the C language.

Do yourself a big favor. Do not write code that depends on this difference! Instead, write your program this way.

int x,y; x = 10; y = x; x++;

cout << y << endl;

int a,b; a = 10; a++;

b = a;

cout << b << endl;

Missing thus far from our discussion is exponentiation. There is no exponentiation operator in C++. Rather, one may use the pow procedure. To do so, one needs to load the cmath header file using the following preprocessor directive.

#include <cmath>

With this in place, you can compute ab with the expression pow(a,b).

The cmath header defines a number of standard mathematical functions and constants. For example, exp is the usual ex function and M_PI gives the value1 of π. A classic problem (that one ought to solve without a computational aid) is to determine which is greater: eπ or πe. The following program settles the issue.

Program 2.6: A program to calculate eπ and πe.

1 #include <iostream>

2#include <cmath>

3using namespace std;

4

5/**

6* Which is larger, pi to the e or e to the pi? We calculate both to

7* find out.

8 */

9

10int main() {

11double e = exp(1.);

12double pi = M_PI;

13

1The symbol M PI is not completely standardized. If your compiler complains that M PI is undefined, add the line const double M PI = 3.14159265358979; to the beginning of your program.

22

C++ for Mathematicians

14cout << "e to the pi is " << exp(pi) << endl;

15cout << "pi to the e is " << pow(pi,e) << endl;

16}

Here is the output of the program.

e to the pi is 23.1407pi to the e is 22.4592

2.6Comparisons and Boolean operations

C++ provides comparison operators for testing numbers for equality and order. Each of these operators results in a bool. In this chart, x and y are variables, and x and y are their respective values.

Expression

Result

x == y

true iff x = y

x != y

true iff x 6= y

x < y

true iff x < y

x <= y

true iff x ≤ y

x > y

true iff x > y

x >= y

true iff x ≥ y

Boolean values can be combined with the standard logical operations. In the following chart x and y are of type bool, and x and y are their values.

Expression

Description

!x

¬x, i.e., not x

x && y

x y, i.e., logical and

x

|| y

x y, i.e., logical or

x

ˆ y

x Y y, i.e., exclusive or

These logical connectives are often used in conjunction with comparison operators in an expression such as

( (x == y) && (y <= z) )

which evaluates to true if and only if x = y ≤ z. Although the following is syntactically correct,

x == y <= z

it is not equivalent to x = y ≤ z. Here one of x == y or y <= z is evaluated first and then that results in a bool value. Unfortunately, bool values are convertible to integers, so the next comparison can take place. The expression x == y <= z is poor programming because it is not clear to the reader which comparison is evaluated first. (C++ has specific rules for this, but you should not rely on them.) Furthermore, the use of a bool as a numeric type is a sneaky trick, and sneaky tricks (regardless of how clever they may be) make code confusing and hard to understand.

Numbers

23

2.7Complex numbers

C++ handles complex numbers nearly as easily as real numbers. Although the real types such as double are part of the C++ core, the complex type requires the inclusion of a header file and a slightly different syntax for variable declaration.

First, because complex numbers are not part of the C++ core, we need to issue the preprocessor directive #include <complex>.

Second, we have some choices on what sort of complex numbers we want. For example, we may want complex numbers in which the real and imaginary parts are of type float, or for greater accuracy, both of type double. On the other hand, we may be interested in working with Gaussian integers, in which case we want the real and imaginary parts to be of type int or long. Fortunately, all these choices are available to us. Here is how we declare variables:

complex<double> z;

//

z’s real and imaginary parts are of type double

complex<long> w;

//

w is a Gaussian integer

Next, we need to be able to assign complex values to these newly declared complex variables. We do that as follows.

z

=

complex<double> (4., -0.5);

//

z

is

set

to

4-0.5i

w

=

complex<long> (6,2);

//

w

is

set

to

6+2i

Recall that in order to convert (cast) an int into a double, we used an expression of the form double(x) (where x was a variable of type int). The same idea applies here. To create a complex<double> we use the type name, but this time with two arguments, as in complex<double>(4.,-0.5).

Typing complex<double> repeatedly can be annoying. Fortunately, C++ enables us to create an abbreviation. The statement

typedef complex<double> C;

defines the symbol C as a substitute for complex<double>. Once we have created this abbreviation, to declare a variable to be of type complex<double> we only need to type C z; and z has the desired type. To assign z a value, we can simply write z = C(6,-3); and now z has the value 6 −3i.

Complex variables are printed on the screen as ordered pairs. If z has value 6 −3i, then cout << z << endl; prints (6,-3) on the computer’s screen.

The following program illustrates these ideas. Note the unusual way in which we extract the real and imaginary parts of a complex variable (lines 26–27). It is too soon for us to explain this unusual syntax, but all is revealed in time.

Program 2.7: A program to demonstrate C++’s ability to handle complex numbers.

1 #include <iostream>

2#include <complex>

3using namespace std;

4

24

C++ for Mathematicians

5/**

6* A program to illustrate the use of complex numbers.

7

*/

8

 

9typedef complex<double> C;

10

11int main() {

12C x(3,4); // define x = 3+4i

13

C z;

// declare z to be complex

14z = C(2,7); // assign z = 2+7i

15C i(0,1); // define i = sqrt(-1)

16

17cout << "z = " << z << endl;

18cout << "x = " << x << endl;

19cout << "z+x = " << z+x << endl;

20cout << "z*x = " << z*x << endl;

21cout << "z/x = " << z/x << endl;

22

23z = 5. - 4.*i;

24cout << "Now z = " << z << endl;

25

26cout << "The real part of z is " << z.real()

27<< " and the imaginary part is " << z.imag() << endl;

28

 

29

return 0;

30

}

 

 

 

 

The output of this program follows.

 

 

 

 

z =

(2,7)

 

 

 

 

 

 

x =

(3,4)

 

 

 

 

z+x

= (5,11)

 

 

 

 

z*x

= (-22,29)

 

 

 

 

z/x

= (1.36,0.52)

 

 

 

 

Now

z = (5,-4)

 

 

 

 

The

real part of z is 5 and the imaginary part is -4

 

 

 

 

 

 

If you plan to work with complex numbers, the typedef abbreviation is conve-

nient, as is defining the variable i to be −1. A convenient way to do this is to create your own header file to #include at the start of your program. The name of a header file that you create is some base name of your choosing plus a .h extension. For example, you could name the header file my_complex.h, but my preference is complexx.h with the extra x for extension.

Here is the complexx.h header file.

Program 2.8: A header file, complexx.h, containing convenient definitions for working with complex numbers.

1/**

2* @file complexx.h

3* @brief A header file that adds convenient extensions for working

4

* with complex numbers.

5*/

6

Numbers

25

7 #ifndef COMPLEXX_H

8#define COMPLEXX_H

9

10#include <complex>

11using namespace std;

12

13/**

14* We define C to be an abbreviation for complex<double>.

15*/

16typedef complex<double> C;

17

18/**

19* We define i to be a constant equal to sqrt(-1), i.e., C(0.,1.).

20*/

21const C i = C(0., 1.);

22

23 #endif

When we want to use this header file, we employ a slightly different version of the #include directive. We write this at the start of our program:

#include "complexx.h"

We can now use C and i as desired.

There’s a fair amount going on in the complexx.h file, but the heart of the mat-

ter can be found on lines 16 and 21 where we define C to be an abbreviation for

complex<double> and i to be a constant equal to −1.

Line 21 contains a new C++ keyword, const. By declaring i to be of type const C we are saying two things. First, i represents a quantity of type C (which, in turn, means complex<double>). Second, i cannot be changed later in our program.

Because i is declared outside any procedure (e.g., it is not enclosed between the

curly braces of main()), it is a global constant. The use of global constants is good.

If your work makes extensive use of the golden mean, φ = 12 (1 + 5), you could create a header file containing the following line.

const double phi = (1. + sqrt(5.))/2.;

Side comment: It is possible to create global variables, but this is a bad practice that should be avoided if at all possible. The problem is that one part of your program might modify a global variable causing unexpected behavior later in another part of your program. A common source of confusion and bugs in computer programs are the side effects procedures might have. We try to rein these in as much as possible. Global variables are antithetical to this effort.

There are a number of other parts of complexx.h that we need to explain. Let’s work through them one at a time.

Lines 1–5 are a comment. Without going into detail, these comments give a description of what this file does. The @file and @brief are instructions for a program called Doxygen that we describe later. Suffice it to say that by including these markers here, the Doxygen program can use comments like this to create beautiful Web pages that you can use to look up what your