Vous êtes sur la page 1sur 4

9.

Finding square root by Newtons iteration


We have used Python to write tiny programs, programs which are less than ten lines of code. Most useful programs are much longer; for example, the core of the Linux operating system (called the kernel) has a few million lines of code written in the C programming language! Such a system is the collective effort of hundreds of programmers. These programmers spend their time reading code written by others, making improvements and correcting errors. As a programmer, it is your responsibility to write clear, readable code. In this chapter, we examine how to use functions to achieve this objective.

9.1. Programming as Essay writing


How do you go about writing an essay (or a book, newspaper article, whatever)? First, you form an idea in your mind as to what exactly you wish to convey to your audience. The message you wish to convey should be presented in a structured manner; you will divide your essay into sections, subsections and paragraphs. You will make sure that ideas flow logically from one section to the next. If you are trying to explain something very complex, you will first introduce your audience to simpler (but related) ideas and then try to build up the more complex idea on the basis of the simpler ones. You will uphold clarity as one of your biggest virtues. Writing a program is similar to composing an essay. Ultimately, your program has to run on a computer and provide correct output. But it should also be easy for other people to read, understand and modify your code. Lets study the Python implementation of a simple square root finding algorithm to understand how functions can be used to write clear code (the code I have presented here is the Python version of a program presented in the famous book Structure and Interpretation of Computer Programs).

9.2. Finding square roots


There is a very simple technique for calculating the square root of a number based on what is called the Newtons method. Lets say you wish to calculate square root of 16 (we will call this X). We make a guess that the root is 1:
X = 16, Guess = 1.0

Now, is this guess good enough? We can find out by taking the square of Guess and checking whether it is close to X. In this case, our guess is not good enough. So, we will improve our initial guess; our improved guess should be, according to Newtons method:
Average of two numbers: Guess and X/Guess

In this case, it will be average of 1 and 16, that is 8.5. This improved guess is also not good enough, so we shall improve it by again taking average of Guess and X/Guess where Guess is now 8.5. The value we get will be:
(8.5 + 16/8.5) / 2 = 5.19

We repeat this process a few times:

(5.19 + 16/5.19) / 2 = 4.13 (4.13 + 16/4.13) / 2 = 4.00

In just two more steps, we reach close enough to the required value!

9.3. Writing a square root finding program


In describing the root finding algorithm, we used terms like improve, average, good enough etc. The Python programming language has no idea what these terms stand for. But we can teach Python the meaning of these words by defining functions whose names are improve, average and good_enough. Lets give it a try.

9.3.1. Defining average


Here is our function average:
>>> def average(a, b): ... return (a + b) / 2.0 ... >>> average(1, 2) 1.5 >>>

9.3.2. Defining improve


An improved guess is average of Guess and X/Guess. So, we define improve as:
>>> def improve(guess, x): ... return average(guess, x/guess) ... >>> improve(1.0, 16) 8.5 >>>

We give the names guess and x to the parameters of improve; we could have as well used any other names, say, a and b. The use of the names guess and x makes the code more readable. Note the way we are using one function to build another (improve makes use of average).

9.3.3. Defining good_enough


We can say that p is square root of q if the difference between square of p and q is less than a small number say 0.001. We use this idea to define a boolean function called good_enough which checks whether its parameter guess is good enough to be the square root of x:
>>> from math import * >>> def good_enough(guess, x): ... d = abs(guess*guess - x) ... return (d < 0.001) ... >>> good_enough(1, 16) False >>> good_enough(4.0, 16) True

>>>

The import statement is required because we are using a function called abs which is defined in the math library. abs returns the absolute value of its argument:
>>> abs(1) 1 >>> abs(-1) 1 >>>

We need to take the absolute value of the difference between guess*guess and x because guess*guess may be either greater than x or less than x; unless the absolute value is taken, this will cause problem when comparing with 0.001 in the next line. The statement:
(d < 0.001)

is either True or False depending on whether d is less than or greater than 0.001.

9.3.4. Defining the square root function


The square root algorithm is very simple; basically, it says:
As long as the guess is not good enough, keep on improving the guess

Here is a function which implements this algorithm:


>>> def square_root(guess, x): ... while(not good_enough(guess, x)): ... guess = improve(guess, x) ... return guess ... >>> square_root(1, 16) 4.0000006366929393 >>> square_root(1, 25) 5.000023178253949 >>>

For finding square root of 16, we will call our function like this:
square_root(1, 16)

This will result in the parameter guess getting the value 1 and parameter x getting the value 16. In the condition part of the while loop, we have written:
not good_enough(guess, x)

Python calls the function good_enough with parameters 1 and 16 - good_enough will return False. The not operator, when it acts on the boolean value False, returns the value True. So we have the boolean value True in the condition part of the while loop. As condition is true, the body will get executed. The body is:
guess = improve(guess, x)

The improve function, given the values 1 and 16, returns 8.5. This becomes the new value of guess. The condition checking part of the while loop gets executed again; function good_enough gets called with parameters 8.5 and 16 and it returns False. The not operator returns True and so the body of the loop gets executed once more. This process stops only when good_enough returns True (in which case the condition becomes False because not True is False). If:
good_enough(guess, x)

is True, that means guess may be taken to be square root of x. When the loop terminates, the next statement:
return guess

returns the value of guess as the value of the function square_root(1, 16). The only problem with our square_root function is that we have to call it with two parameters, the first one being the initial value for guess. It is more natural to have a square root function which takes only one parameter - the number whose square root is required. We can manage this very easily by defining an additional function:
>>> def my_sqrt(x): ... r = square_root(1, x) ... return r ... >>>

9.4. Conclusion
We developed our square root function on top of other, simpler functions. Each function we wrote performed one simple computation and was easy to read and understand. The final square_root function too was very simple (all the hard work was being done by the other functions). Finding the square root is definitely not a big deal, and real life programs are incredibly more complex than this toy example. But the approach we have taken scales well - most big programs are written this way, as a collection of simple functions.

Vous aimerez peut-être aussi