exercise 1.6

平方根を求めるアルゴリズム sqrt-root.
ビルトイン関数に含まれているのだけど、アルゴリズムの演習って事で、
再実装してみる。
まずは、Schemeで。

 (define (sqrt n)
  (define (abs n) (if (< n 0) (-n) n))
  (define (sqare n) (* n n))
  (define (average a b) (/ (+ a b) 2))
  (define (improve guess n) (average guess (/ n guess)))
  (define (good-enough? guess n) (< (abs (- (square guess) n)) 0.001))
  (define sqrt-iter (guess n)
   (if (good-enough? guess n)
    guess
    (sqrt-iter (improve guess n) n)))
  (sqrt-iter 1.0 n))

続いて OCaml

 let sqrt n =
  let abs               n = if n < 0 then (-.n) else n      and
      square            n = n *. n                          and
      average         a b = (a +. b) /. 2.0                 and
      improve     guess n = average guess (n /. guess)      and
      good_enough guess n = abs((square guess) -. n) < 0.001 in
  let rec sqrt_iter guess n =
   if good_enough guess n then
    guess
   else
    sqrt_iter (improve guess n) n
  in 
 sqrt_iter 1.0 n;;

ローカル関数(?)の定義って and で良かったのかな。(未検証)
駄目なら let ... in で。

その次は、HaskellOCaml と殆ど同じだけど、
型を気にしなくてもいいのと、再帰の宣言がいらないので楽。
ただし、sqrt の定義の上書きは無理みたい。

 my_sqrt n = 
  let abs                n = if n < 0 then (-n) else n       in
  let square             n = n * n                           in
  let average          a b = (a + b) / 2                     in
  let improve      guess n = average guess (n / guess)       in
  let good_enough  guess n = abs((square guess) - n) < 0.001 in
  let my_sqrt_iter guess n =
   if good_enough guess n then
    guess
   else
    my_sqrt_iter (improve guess n) n
   in
  my_sqrt_iter 1.0 n;;

OCamlHaskell は、まだ始めたばかりなので、
コーディングスタイルがまだ解らない。パディングしてもいいのかな。
Pythonでは推奨されていないのだけど、
ここでは保守性より読みやすさ重視なので(・・・と断りを入れてから)

def sqrt(num):
 abs         = lambda       x : (x < 0) and -x or x
 square      = lambda       x : x * x
 average     = lambda     x,y : (x+y)/2
 improve     = lambda guess,n : average(guess,(n/guess))
 good_enough = lambda guess,n : abs(square(guess)-n) < 0.001

 def sqrt_iter(guess,n):
  if good_enough(guess,n):
   return guess 
  else:
   sqrt_iter(improve(guess,n), n)

 sqrt_iter(1.0, num)

最後に、C 。

 #define ABS(N)               *1
 #define SQUARE(N)            *2
 #define AVERAGE(A,B)         (((A)+(B))/2)
 #define IMPROVE(GUESS,N)     (AVERAGE*3<0.001)

 float sqrt_iter(float guess, int n){
  if (GOOD_ENOUGH(guess, n))
   return guess;
  else
   return sqrt_iter(IMPROVE(guess,n), n);
 }
 float my_sqrt(guess, n){
  return sqrt_iter(1.0, n);
 }

*1:N)<0 ? (-N) : (N

*2:N)*(N

*3:GUESS),((N)/(GUESS))) #defien GOOD_ENOUGH(GUESS,N) (ABS(SQUARE(GUESS)-(N