Debugging Newton's method for square roots

I am new to Haskell and need help in debugging my code. I wrote the following function for calculating square roots using Newton's method: my_sqrt :: Float -> Float my_sqrt x = improve 1 x where improve y x = if abs (y * y - x) < epsilon then y else improve ((y + (x/y))/ 2) x epsilon = 0.00001 This works for several examples that I tried out but goes into an infinite loop for my_sqrt 96. How do I go about debugging this code in GHC or Hugs? (The equivalent code is well-behaved on MIT Scheme)

Vraj Mohan
I am new to Haskell and need help in debugging my code.
I wrote the following function for calculating square roots using Newton's method:
my_sqrt :: Float -> Float my_sqrt x = improve 1 x where improve y x = if abs (y * y - x) < epsilon then y else improve ((y + (x/y))/ 2) x epsilon = 0.00001
This works for several examples that I tried out but goes into an infinite loop for my_sqrt 96.
Generally it's better to separate out the different parts of the algorithm. So sqrt_step x candidate = (candidate + x/candidate)/2 Now you can try take 20 $ iterate (sqrt_step 2) 1 and watch the convergence. When you're happy with that, you can use something like “head . dropWhile unconverged”.
(The equivalent code is well-behaved on MIT Scheme)
Is it? Is there equivalent code to “my_sqrt :: Float -> Float”? (that might be pertinent). -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk http://www.chaos.org.uk/~jf/Stuff-I-dont-want.html (updated 2006-09-13)

I wrote:
Vraj Mohan
wrote: (The equivalent code is well-behaved on MIT Scheme)
Is it? Is there equivalent code to “my_sqrt :: Float -> Float”? (that might be pertinent).
By which I mean "HINT". (And one of the places to look for bugs is where you have hand coded a constant without due consideration of the implications). -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk http://www.chaos.org.uk/~jf/Stuff-I-dont-want.html (updated 2006-09-13)

Vraj Mohan wrote:
my_sqrt :: Float -> Float my_sqrt x = improve 1 x where improve y x = if abs (y * y - x) < epsilon then y else improve ((y + (x/y))/ 2) x epsilon = 0.00001
This works for several examples that I tried out but goes into an infinite loop for my_sqrt 96. How do I go about debugging this code in GHC or Hugs?
1) As Jon said, by seperating the iteration from the selection of the result. iterate, filter, head, etc. are your friends. Makes the code more readable and maintainable, too. 2) By learning more about floating point numbers. There is no Float y such that | y*y - 96 | < 0.00001. That's why such an iteration is better terminated not when the result is good enough, but when it stops getting better. It's also the reason why you code might work with -fexcess-precision or in an untyped language or with the next or previous compiler release or on rainy days or whatever else. Udo. -- Walk softly and carry a BFG-9000.

Hello Udo, Sunday, October 15, 2006, 7:02:05 PM, you wrote:
stops getting better. It's also the reason why you code might work with -fexcess-precision or in an untyped language or with the next or previous compiler release or on rainy days or whatever else.
"our brand-new GHC 22.6 has a mood! on the rainy days it meditates about life meaning and can make some errors due to inattention. we have added to our BugTrac system field where you should describe weather at the moment of bug - this will greatly simplify our debugging work" :) -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

On Sun, Oct 15, 2006 at 12:17:20PM +0000, Vraj Mohan wrote:
I am new to Haskell and need help in debugging my code.
I wrote the following function for calculating square roots using Newton's method:
my_sqrt :: Float -> Float my_sqrt x = improve 1 x where improve y x = if abs (y * y - x) < epsilon then y else improve ((y + (x/y))/ 2) x epsilon = 0.00001
This works for several examples that I tried out but goes into an infinite loop for my_sqrt 96. How do I go about debugging this code in GHC or Hugs?
(The equivalent code is well-behaved on MIT Scheme)
Hi Vraj, 1. First, generally about debugging: I asked this question a month ago, on this mailing list. See this thread: http://www.haskell.org/pipermail/haskell-cafe/2006-September/017858.html 2. Newton's method is not guaranteed to converge. For examples, and a nice introduction to uni- and multivariate rootfinding, see Numerical Methods in Economics, Kenneth L Judd, Chapter 5. I suggest that you use bisection, it is much more robust. I have written a bisection routine which I have been planning to post after a bit of testing, maybe you will find it useful: bisection tol reltol f a b | tol < 0 || reltol < 0 = error "bisection needs positive tolerances" | abs fa <= tol = Just a -- a is a root | abs fb <= tol = Just b -- b is a root | fa*fb > 0 = Nothing -- IVT not guaranteed | a > b = bis b a fb fa -- exchange endpoints | otherwise = bis a b fa fb -- standard case where fa = f a -- function evaluated only once at each fb = f b -- endpoint, store them here bis a b fa fb = let m = (a+b)/2 fm = f m in if (b-a) <= reltol*(1+abs(a)+abs(b)) || abs fm <= tol then Just m -- implicit assumption: fa * fb > 0 else if fm*fa < 0 -- new interval: [a,m] then bis a m fa fm else bis m b fm fb -- new interval: [m,b] -- uniroot is a specialisation of bisection, with commonly used -- tolerance values uniroot = bisection 1e-20 1e-15 Untested code: mysqrt x = uniroot f 0 x where f y = y**2-x It will give you a Maybe a type value, ie Nothing for negative numbers. Comments about my code are of course welcome, I am a newbie myself. Best, Tamas

G'day all.
Quoting Tamas K Papp
2. Newton's method is not guaranteed to converge.
For computing square roots, it is. The square root function is exceedingly well-behaved. But you can make things better by choosing a smart initial estimate. The initial estimate in this version is so good that you only need a fixed number of iterations, so there are no loops here. mysqrt :: Double -> Double mysqrt x | x <= 0 = if x == 0 then 0 else error "mysqrt domain error" | r == 1 = sqrt2 * sqrtx | otherwise = sqrtx where (q,r) = exponent x `divMod` 2 sqrtx = scaleFloat q (sqrtSignificand (significand x)) -- Feel free to add more digits if this is insufficient sqrt2 = 1.41421356237309504880168872420969807856967 -- Compute the square root of a number in the range [0.5,1) sqrtSignificand :: Double -> Double sqrtSignificand x = iter . iter . iter $ d0 where -- d0 is a third-order Chebyshev approximation to sqrt x x' = x * 4.0 - 3.0 d2 = -6.177921038278929e-3 d1 = 2 * x' * d2 + 0.14589875298243973 d0 = x' * d1 - d2 + 0.5 * 1.7196949654923188 iter sx = 0.5 * (sx + x / sx) Cheers, Andrew Bromage

Vraj Mohan wrote:
This works for several examples that I tried out but goes into an infinite loop for my_sqrt 96. How do I go about debugging this code in GHC or Hugs?
(The equivalent code is well-behaved on MIT Scheme)
There was some excellent advice in the other responses, but I thought it worth mentioning that your Haskell code converges if you step up from Float -> Float to Double -> Double.

Clifford Beshers
There was some excellent advice in the other responses, but I thought it worth mentioning that your Haskell code converges if you step up from Float -> Float to Double -> Double.
Used to be faster, too, IIRC. Is that still the case? -k -- If I haven't seen further, it is by standing in the footprints of giants
participants (8)
-
ajb@spamcop.net
-
Bulat Ziganshin
-
Clifford Beshers
-
Jón Fairbairn
-
Ketil Malde
-
Tamas K Papp
-
Udo Stenzel
-
Vraj Mohan