class MoreMath::ContinuedFraction
…
a_4 + —–
b_5
a_3 + ———-
b_4
a_2 + —————
b_3
a_1 + ——————–
b_2
a_0 + ————————-
b_1
This class implements a continued fraction of the form:
def self.for_a(arg = nil, &block)
Creates a ContinuedFraction instances and passes its arguments to a call
def self.for_a(arg = nil, &block) new.for_a(arg, &block) end
def self.for_b(arg = nil, &block)
Creates a ContinuedFraction instances and passes its arguments to a call
def self.for_b(arg = nil, &block) new.for_b(arg, &block) end
def a(n, x = nil)
def a(n, x = nil) result = if x @a[n, x] else @a[n] end and result.to_f end
def b(n, x = nil)
def b(n, x = nil) result = if x @b[n, x] else @b[n] end and result.to_f end
def call(x = nil, epsilon = 1E-16, max_iterations = 1 << 31)
accuracy +epsilon+ and +max_iterations+ as the maximum number of
Evaluates the continued fraction for the value +x+ (if any) with the
def call(x = nil, epsilon = 1E-16, max_iterations = 1 << 31) c_0, c_1 = 1.0, a(0, x) c_1 == nil and return 0 / 0.0 d_0, d_1 = 0.0, 1.0 result = c_1 / d_1 n = 0 error = 1 / 0.0 $DEBUG and warn "n=%u, a=%f, b=nil, c=%f, d=%f result=%f, error=nil" % [ n, c_1, c_1, d_1, result ] while n < max_iterations and error > epsilon n += 1 a_n, b_n = a(n, x), b(n, x) a_n and b_n or break c_2 = a_n * c_1 + b_n * c_0 d_2 = a_n * d_1 + b_n * d_0 if c_2.infinite? or d_2.infinite? if a_n != 0 c_2 = c_1 + (b_n / a_n * c_0) d_2 = d_1 + (b_n / a_n * d_0) elsif b_n != 0 c_2 = (a_n / b_n * c_1) + c_0 d_2 = (a_n / b_n * d_1) + d_0 else raise Errno::ERANGE end end r = c_2 / d_2 error = (r / result - 1).abs result = r $DEBUG and warn "n=%u, a=%f, b=%f, c=%f, d=%f, result=%f, error=%.16f" % [ n, a_n, b_n, c_1, d_1, result, error ] c_0, c_1 = c_1, c_2 d_0, d_1 = d_1, d_2 end n >= max_iterations and raise Errno::ERANGE result end
def for_a(arg = nil, &block)
argument to the block. If a_n is dependent on an +x+ value (see the call
block has to return the value for a_n when +n+ is passed as the first
has to respond to an integer index n >= 0 and return the value a_n. The
This method either takes a block or an argument +arg+. The argument +arg+
def for_a(arg = nil, &block) if arg and !block @a = arg elsif block and !arg @a = block else raise ArgumentError, "exactly one argument or one block required" end self end
def for_b(arg = nil, &block)
argument to the block. If b_n is dependent on an +x+ value (see the call
block has to return the value for b_n when +n+ is passed as the first
has to respond to an integer index n >= 1 and return the value b_n. The
This method either takes a block or an argument +arg+. The argument +arg+
def for_b(arg = nil, &block) if arg and !block @b = arg elsif block and !arg @b = block else raise ArgumentError, "exactly one argument or one block required" end self end
def initialize
Creates a continued fraction instance. With the defaults for_a { 1 } and
def initialize @a = proc { 1.0 } @b = proc { 1.0 } end
def to_proc
Returns this continued fraction as a Proc object which takes the same
def to_proc proc { |*a| call(*a) } end