• 沒有找到結果。

Floating-point types

Like integers, floating-point numbers are represented in a fixed amount of internal memory and therefore have size limitations. For floating-point numbers, however, the limitation on memory affects the precision of the data (how many significant digits are available) as well as the range. Because precision is a function of the hardware, the precision of a floating-point number may differ from machine to machine. On one

machine, for example, floating-point numbers might be limited to 10 significant digits. On that machine, the values 1.0 and 1.00000000001 will appear to be the same because the computer cannot represent the latter number exactly.

As with integers, C provides three types of floating-point numbers. The type float is the least precise, but takes less memory than the type double. Over the last decade, however, computer memory had gotten cheaper, and most C programmers now tend to use the more precise type double for all floating-point data—a practice followed in this text. All calculations involving values of type float or double are performed in C as if they had been declared as type double; the data type affects only how the values are stored.

For certain extremely exacting numerical computations, however, the type double may not be sufficiently precise. For applications that require extremely high precision, the ANSI standard also includes a type called long double, although this type is rarely necessary in practice.

SUMMARY

In this chapter, you learned several general strategies for designing algorithms. The examples presented were chosen from classical mathematics, mostly because mathematics provides an interesting set of problems that you can solve without knowing about data types other than numbers. As you learn about other data types in later chapters, you will discover that the algorithmic techniques presented here can be applied to other sorts of problems as well.

Important points introduced in this chapter include:

 There are often many different algorithms that can solve a particular problem.

Choosing the algorithm that best fits the application is an important part of your task as a programmer.

 When choosing between different algorithms, you need to consider many different factors, including efficiency, maintainability, and clarity. Choosing a particular algorithm will often involve evaluating tradeoffs between these qualities.

 You should never sacrifice correctness as you work to improve other aspects of your program.

 Proving that a program is correct is an extremely difficult task. In most cases, through testing is necessary to increase your confidence that a particular solution is correct.

Even with good testing, however, subtle errors may remain.

 Brute-force algorithms are those that check every possibility without trying to be clever. Such algorithms are usually easy to understand but are likely to be extremely inefficient.

 Successive approximation often provides a mechanism by which guesses can be transformed into solutions by continually improving the accuracy of the guess.

 Error conditions that occur during a program can be reported to the user by calling the Error function, which is defined in the genlib library.

 Many mathematical functions can be approximated using the technique of series expansion.

REVIEW QUESTIONS

1. What are the three properties that are required for a strategy to be considered an algorithm?

2. What is a loop invariant?

3. Explain in your own words why it is unnecessary to consider factors greater than

n

when you are testing to see if n is a prime.

4. One of the common pitfalls boxes in this chapter makes a suggestion for improving the efficiency of loops. What method does it suggest?

5. What are some of the factors you would consider in choosing between alternative algorithms for solving a particular problem?

6. In the examples that used Euclid’s algorithm to calculate the GCD of x and y, x is always larger than y. Does this matter? What happens if x is smaller than y?

7. When you have written a program that converges toward a solution, how do you know when to stop?

8. In what ways does the Error function differ in its behavior from printf? 9. What is Zeno’s paradox?

10. I evaluating a power series, is it better to compute each new term directly or by using the preceding term? Why?

11. The control line for the while loops used to calculate the sum of each power series looks like this?

While (sum != sum + term)

At first glance, this test seems unusual. Mathematically, it should be possible by simplify this test to

while (term != 0))

Programs that use this second test require much longer to run. Why?

12. Why is it necessary to include the special case test for 0 in the Taylor series implementation of Sqrt?

PROGRAMMING EXERCISES

1. Although this chapter has focused on mathematical algorithms, the Greeks were fascinated with algorithms of other kinds as well. In Greek mythology, for example, Theseus of Athens escapes from the Minotaur’s labyrinth by taking in a ball of string, unwinding it as he goes along , and then following thepath of string back to the exit.

Theseus’s strategy represents an algorithm for escaping from a maze, but it is not the only algorithm he could have used to solve this problem. For example, if a maze has no internal loops, you can always escape by following the right hand rule, in which you always keep your right hand against the wall. This approach may lead you to backtrack from time to time, but it does ensure that you will eventually find the

opening to the outside.

For example, imagine that Theseus is in the maze shown below at the position marked by the Greek letter theta (Θ ):

Θ

To get out, Theseus walks along the path shown by teh dotted line in the next diagram, which he can do without taking his right hand off the wall.

Θ

Suppose you have been asked to write a program for a robot named Theseus to implement the right-hand rule. You have access to a library the contains these functions:

void MoveForward (void); /* Move forward to the next square */

void TurnRight (void); /* Turn right without moving */

void TurnLeft (void); /* Turn left without moving */

bool IfFacingWall (void); /* TRUE if Theseus is facing a wall */

bool IfOutside (void); /* TRUE if Theseus has escaped */

Use the functions to write a procedure EscapeFromMaze that implements the algorithm suggested by the right-hand rule.

2. In many cases, it is not enough to know whether a number is prime; sometimes, you need to know its factors. Every positive integer greater than 1 can be expressed as a product of prime numbers. This factorization is unique and is called the prime factorization. For example, the number 60 can be decomposed into the factors 2×2×3×5, each of which is prime. Note that the same prime can appear more than once in the factorization.

Write a program to display the prime factorization of a number n. The following is a sample run of the program:

Enter number to be factored: 60  2 * 2 * 3 * 5

3. Greek mathematicians took a special interest in numbers that are equal to the sum of their proper divisors (a proper divisor of n is any divisor less than n itself). They called such numbers perfect numbers. For example, 6 is a perfect number because it is the sum of 1, 2, and 3, which are the integers less than 6 that divide evenly into 6.

Similarly, 28 is a perfect number because it is the sum of 1, 2, 4, 7,and 14.

Write a predicate function IsPerfect that takes an integer n and returns TRUE if n is perfect, and FALSE otherwise. Test your implementation by writing a main program that uses the IsPerfect function to check for perfect numbers in the range 1 to 9999 by testing each number in turn. When a perfect number is found, your program should display it on the screen. The first two lines of output should be 6 and 28. You program should find two other perfect numbers in that range as well.

4. After you have gotten the perfect number program from exercise 3 to work, think carefully about the algorithm you’ve used. Write a new version of the program that improves the efficiency of the algorithm without sacrificing its correctness.

5. Modify Newton’s algorithm as presented in the text so that it calculates cube roots instead of square roots. Express the algorithm in the form of a function CubeRoot that takes a double and returns another double, which is the cube root of the argument. The creative part of this problem is figuring out what numbers you should average to obtain a new guess on each cycle of the loop. If g, for example, lies to one side of the cube root of n, what value can you compute using n and g that would be approximately as close to the root but on the opposite side? If you can find such a value, averaging the two will yield a result that is closer to the actual answer.

6. Mathematicians and other scientists sometimes find unexpected applications for power series approximation. In 1772, the astronomer J.E. bode proposed a rule for calculating the distance from the sun to each of the planets known at that time. To apply that rule, which subsequently became known as Bode’s law, you begin by writing down the sequence

b1 = 1 b2 = 3 b3 = 6 b4 = 12 b5 = 24 b6 = 48

where each subsequent element in the sequence is twice the preceding one. It turns out that an approximate distance to the ith planet can be computed from this series by applying the formula

di =

10 4  b

1

The distance is given in astronomical units; an astronomical unit (AU) is the average distance from the sun to the earth, which is approximately 93,000,000 miles.

Except for a disconcerting gap between Mars and Jupiter, Bode’s law gives reasonable approximations for the distances to the seven planets known in Bode’s day:

Mercury 0.5 AU

Venus 0.7 AU

Earth 1.0 AU

Concern about the gap in the sequence led astronomers to discover the asteroid belt, which they decided was left over after the destruction of a planet that had once orbited the sun at distance specified by the missing entry in Bode’s table.

Write a program to display the above table, using Bode’s formula to calculate the distances.

7. The technique of series approximation can be used to compute approximations of the mathematical constantπ . One of the simplest series that involvesπ is the following:

8. Unfortunately, the series used to approximateπ in exercise 7 converges extremely slowly. Even after 10,000 terms have been evaluated, the approximation is correct only to four digits. Using this technique to compute π to the limit of floating-point precision would be impractical. The following series converges much more quickly:

 information to write a program that calculatesπ to the limit of floating-point accuracy.

Display your answer with 10 decimal places.

9. You can also approximateπ by approximating the area bounded by a circular arc.

Consider the quarter circle

Which has a radius r equal to two inches. From the formula for he area of a circle, you can easily determine that the area of the quarter circle should beπ square inches.

You can also approximate the area computationally by adding up the areas of a series of rectangles, where each rectangle has a fixed width and the height is chosen so that the circle passes through the midpoint of the top of the rectangle. For example, if you

divide the area into 10 rectangles from left to right, you get the following diagram:

The sum of the areas of the rectangles provides an approximation to the area of the quarter circle. The more rectangles there are, the closer the approximation.

For each rectangle, the width w is a constant derived by dividing the radius by the number of rectangles. The height h, on the other hand, varies depending on the position of the rectangle. If the midpoint of the rectangle in the horizontal direction is given by x, the height of the rectangle can be computed using the distance formula

h =

r

2

x

2

The area of each rectangle is then simply h × w.

Write a program to compute the area of the quarter circle by dividing it into 100 rectangles.

10. The mathematical constant e can be computed by expanding the following power series:

 6 !

1

! 5 1

! 4 1

! 3 1

! 2 1

! 1 1 1 e

Write a program that computes the value of e by adding the terms in this series until the program reaches the limit of floating-point precision. Display your answer with 10 significant digits after the decimal point.