[mercury-users] Functional square root approximation : help needed
Terrence Brannon
princepawn at earthlink.net
Thu Apr 26 21:52:17 AEST 2001
When I attempt to compile my program, I get the following errors:
[localhost:~/src/mercury/sqrt] metaperl% mmc -E --infer-all sqrt.m
sqrt.m:072: Error: syntax error in predicate mode declaration: _1(in, in, out).
sqrt.m:004: In definition of predicate `sqrt:main'/2:
sqrt.m:004: error: undefined type `in'/0.
sqrt.m:004: In definition of predicate `sqrt:main'/2:
sqrt.m:004: error: undefined type `out'/0.
sqrt.m:052: In clause for predicate `sqrt:sqrt_iter/3':
sqrt.m:052: warning: variable `GoodEnough' occurs only once in this scope.
sqrt.m:073: In clause for predicate `sqrt:/4':
sqrt.m:073: warning: variable `GoodEnough' occurs only once in this scope.
[localhost:~/src/mercury/sqrt] metaperl%
===== here is my program -- all criticism welcomed
:- module sqrt.
:- interface.
:- pred main(in, out) is det.
:- implementation.
:- import_module float, std_util.
% Section 1.1.7 of Abelson and Sussman
% "Structure and Interpretation of Computeer Programs"
% How does one compute square roots? The most common way is to use
% Newton's method of successive approximations, which says that whenever
% we have a guess y for the value of the square root of a number x, we
% can perform a simple manipulation to get a better guess (one closer to
% the actual square root) by averaging y with x/y. For example, we can
% compute the square root of 2 as follows. Suppose our initial guess
% is 1:
%
% Guess Quotient Average
% 1 (2/1) = 2 ((2 + 1)/2) = 1.5
% 1.5 (2/1.5) = 1.3333 ((1.3333 + 1.5)/2) = 1.4167
% 1.4167 (2/1.4167) = 1.4118 ((1.4167 + 1.4118)/2) = 1.4142
% 1.4142 ... ...
% Mercurally speaking, this is:
:- mode sqrt_guess(in, in, out) is det.
sqrt_guess(Y, X, NewGuess) :-
Quotient = X / Y,
NewGuess = (Y + Quotient) / 2
.
% Continuing this process, we obtain better and better approximations to
% the square root.
%
% Now let's formalize the process in terms of procedures. We start with
% a value for the radicand (the number whose square root we are trying
% to compute) and a value for the guess. If the guess is good enough for
% our purposes, we are done; if not, we must repeat the process with an
% improved guess. We write this basic strategy as a procedure:
% (define (sqrt-iter guess x)
% (if (good-enough? guess x)
% guess
% (sqrt-iter (improve guess x)
% x)))
:- mode sqrt_iter(in, in, out) is det.
sqrt_iter(Guess,X,Answer) :-
GoodEnough(Guess,X,Bool),
(
Bool = yes,
Answer = Guess
;
Bool = no,
sqrt_guess(Guess,X,NewGuess),
Answer = NewGuess
)
.
% We also have to say what we mean by ``good enough.'' The following
% will do for illustration, but it is not really a very good test. (See
% exercise 1.7.) The idea is to improve the answer until it is close
% enough so that its square differs from the radicand by less than a
% predetermined tolerance (here 0.001):
% (define (good-enough? guess x)
% (< (abs (- (square guess) x)) 0.001))
:- mode GoodEnough(in, in, out) is det.
GoodEnough(Guess,X,Bool) :-
Assessment = abs(Guess * Guess - X),
( Assessment < 0.001,
Bool = yes
;
Bool = no
)
.
% Finally, we need a way to get started. For instance, we can always
% guess that the square root of any number is 1
% (define (sqrt x)
% (sqrt-iter 1.0 x))
:- mode main(in,out) is det.
main(X,Answer) :- sqrt_iter(1.0,X,Answer).
--------------------------------------------------------------------------
mercury-users mailing list
post: mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the users
mailing list