Created
December 10, 2011 03:07
-
-
Save peterc/1454432 to your computer and use it in GitHub Desktop.
Square root calculation using Newton-Raphson
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Square root calculation using Newton-Raphson | |
# from Practical Programming (1968) | |
a = 256 | |
x = (1 + a) / 2.0 | |
loop do | |
ox = x | |
x = (x + a.to_f / x) / 2.0 | |
break if x >= ox | |
end | |
puts "The square root of #{a} is #{x}" |
Thought I'd try the SICP approach:
def improve(guess, x)
(guess + (x / guess.to_f)) / 2.0
end
def sqrt_iter(guess, x)
return guess if good_enough?(guess, x)
sqrt_iter improve(guess, x), x
end
def good_enough?(guess, x)
(guess ** 2 - x).abs < 0.001
end
def sqrt(x)
sqrt_iter(1.0, x)
end
puts sqrt(25)
A particularly slow approach in Ruby, though. I think tail recursion optimization is turned off by default.
I don't believe Ruby performs TCO at all, even as an option. Here's a faster sqrt_iter:
def sqrt_iter guess, x
until good_enough? guess, x
guess = improve guess, x
end
return guess
end
In vm_opts.h:
#define OPT_TAILCALL_OPTIMIZATION 0
Supposedly it can also be turned on at runtime, but I didn't have any luck with it when I first noticed the option a year or two ago. Might have another try now as it may be tied up ;-)
I gave it a go. No significant performance gain, as far as I could tell. On the few runs I tried, it was a few percent.
All in the interests of science though since, of course, the iterative solution is quicker anyway ;-)
src = <<-RUBY
def improve(guess, x)
(guess + (x / guess.to_f)) / 2.0
end
def sqrt_iter(guess, x)
return guess if good_enough?(guess, x)
sqrt_iter improve(guess, x), x
end
def good_enough?(guess, x)
(guess ** 2 - x).abs < 0.001
end
def sqrt(x)
sqrt_iter(1.0, x)
end
y = nil
500000.times { y = sqrt(2401) }
puts y
RUBY
RubyVM::InstructionSequence.compile_option = {
:tailcall_optimization => false
}
puts "Tail call optimization is #{RubyVM::InstructionSequence.compile_option[:tailcall_optimization] ? "ON" : "OFF"}"
p RubyVM::InstructionSequence.compile(src, nil, nil, 1).eval
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks! I'll have to check that out. I'm not sure why I don't remember it because I've done about a third of SICP in the past.
The technique used in this gist is not as good as it could be, but I wanted to keep it authentic to the ALGOL method outlined in that book from 1968 ;-)