[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