In this session, we are going to apply what we learned so far in a larger
example. The task is to develop a square root
function using Newton's method. That's the first time that we need more
than a couple of lines to actually express a program and we will learn new techniques
and new tools for doing so. So, what that means is that we want to
define a function with the signature. It takes a double and gives me back a
double, and return the value is the square root of its parameter x.
The classical way to compute that is by successive approximations using the method
of Isaac Newton. So, let's see what this method is.
To compute square root of x, we start with an initial estimate value.
It doesn't really matter what that estimate is as long as it's positive.
So, let's pick y = one. And then, we repeatedly improve the
estimate by taking the mean of the old estimate y and the value of x divided by
y, where x is the value we want to draw the root from.
So, it's, let's see that in action. For the value of x, in our example, would
be two. Our initial estimation is one, as usual,
so the initial quotient is two divided by one, that's two, the mean is 1.5.
Now, we plug in 1.5 to our estimation, we get a new quotient of 1.33, a new mean
that you'd see here and you'll see that it converges very quickly to the actual value
of two. So now, we have an abstract algorithm.
Let's see how we would put that into a function that computes that algorithm.
A typical way to code algorithms in functional languages is to go step by
step. So, we take a small task and formulate it
as a function and then probably, that task will need further tasks that then would be
defined in their own function. The first function we want to define is
the actual iteration called the square root Iter, which says, well, if you have a
guess and the value would be one to draw the root from, what do we do?
Well, either we stop the iteration and return the result or we go and do another
iteration step. The predicate that controls that we give
it a name, let's call it, isGoodEnough. So, if my guess is good enough, then I
just can return the guess. If my guess is not yet good enough, then I
have to improve my guess. Let's do that with another function in
prove and call, square root Iter again with the improved guess.
Note that square root Iter is recursive so its right-hand side calls itself.
One peculiarity in Scala is that the return type of a recursive function needs
to be given always whereas, for other functions, it's optional.
The reason for that is that to compute that return type, the Scala compiler would
have to look at the right-hand side and because the square root Iter function is
recursive it's stacked in a cycle. It would need the return type for that to
compute the type for expression. To break the cycle, we require that
recursive functions always have explicit return types.
It actually makes sense even for other publicly used functions to give an
explicitly return type because that's good documentation but it's not required by the
language. Okay.
So, let's implement this in practice. What we're going to see is a new way to
write programs. So far, we have done everything in the
repo. Now, for larger programs, we have
something that is better adapted. We go into Eclipse and we start a
worksheet. So, I take you through the steps one by
one. Here, we have an empty Eclipse thing.
We first start a new project the Scala project.
Call it, demands a name, call it [unknown] for the course.
And then, in the project what we can do is define a package, which is essentially a
directory in which we are going to put all the stuff from this week.
Call this Week one. We don't need to define packages but it's
good practice to keep stuff tidy and ordered.
And then, in that package, we define a new sheet.
It needs a name, let's call it Session. In a worksheet, what we can do is we can
type expressions and have them evaluated, just like in a repo.
So, we can do one plus two and expressions get reevaluated when we hit Save, that
will become [unknown] or Control+S. But the expressions show up on the right
in a different column that you see here. We can also define functions, let's say,
the absolute, absolute function that we've seen before.
So, we could say, well, if x is less than zero - x else x And the repo would answer
the, with the value of the absolute function, well, not the repo, the
worksheet but the two are actually related.
It's just a different mode of presentation.
One thing we can do which is nice, nicer in the worksheet is we can actually go
back and edit expressions and the reevaluation will then show the edited
value. So, it's not just a single line editing
window but a whole window that we can use. So, let's use the worksheet to complete
our square root functions. The first thing I'm going to do is take it
from the slide. So, I select square root Iter here and
paste it inside the worksheet. I can reformat with Control+Shift+F.
So, that would reformat things nicely. But the worksheet still doesn't compile
because, of course, I have two functions here that I haven't yet defined that would
be as good enough and improve. So, for isGoodEnough, let's do that first.
So, is, isGoodEnough takes these same parameters as square root Iter, and it
returns a bullion that says whether we can stop the iteration or whether we need more
steps. So, what could that predicate be?
Well, one way to do it would be to say, well, if we take the current guess here
and we square it. If we are close enough to the original
value x, then guess by itself would be close enough to the desired square root
value. So, let's code that up.
We would say, guess, guess - x, we would have to take the absolute value of that.
And it would have to be smaller than some epsilon value of, say, 001 for the moment.
Okay. So, that was number one.
The second function we need to define is Improve.
And that's now the core of the Newton method, we say, would say, well, it could
take a guess and an X. And to improve the guess, what do we do?
Well, we say, we need to take the mean of the value the current value of guess and
the quotient of x divided by guess. So, to take the average, we would first
sum the two values and then, divide by two.