Skip to content

Instantly share code, notes, and snippets.

@thomthom
Created June 29, 2018 09:58
Show Gist options
  • Save thomthom/dcb8e1e9d9e301272a3733a826e19284 to your computer and use it in GitHub Desktop.
Save thomthom/dcb8e1e9d9e301272a3733a826e19284 to your computer and use it in GitHub Desktop.
Compute arc angle from sagitta and arc length
def time(label)
t = Time.now
yield
puts "#{label}: #{Time.now - t}s"
end
module RosettaCode
def self.sign(x)
x <=> 0
end
def self.find_roots(f, range, step=0.001)
sign = sign(f[range.begin])
range.step(step) do |x|
value = f[x]
if value == 0
# puts "Root found at #{x}"
return x
elsif sign(value) == -sign
# puts "Root found between #{x-step} and #{x}"
return [x+step, x]
end
sign = sign(value)
end
nil
end
def self.find_angle(sagitta, arc_length, step=0.001)
y = sagitta / arc_length
f = lambda { |x| y*x + Math.cos(x/2) - 1 }
result = self.find_roots(f, 1..2, step)
end
end
module BisectApproximation
def self.sign(x)
x <=> 0
end
# (0.0..Math::PI * 2).bsearch { |x| v = f[x]; p [x, v, v <=> 0, (v <=> 0) < 0]; (v <=> 0) < 0 }
def self.resolve(f, range)
sign = sign(f[range.begin])
result = range.bsearch { |x|
(f[x] <=> 0) < 0
}
end
def self.find_angle(sagitta, arc_length)
y = sagitta / arc_length
f = lambda { |x| y*x + Math.cos(x/2) - 1 }
self.resolve(f, 0.0..Math::PI * 2)
end
end
arc_angle = 1.8545904360032246
s = 19.68503937007874 # sagitta
l = 91.26921437023744 # arc length
steps = [0.001, 0.0001, 0.00001, 0.000001]
steps.each { |step|
puts
time("RosettaCode (#{step})") {
result = RosettaCode.find_angle(s, l, step)
puts " Result: #{result}"
puts "Expected: #{arc_angle}"
}
}
puts
time("BisectApproximation") {
result = BisectApproximation.find_angle(s, l)
puts " Result: #{result}"
puts "Expected: #{arc_angle}"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment