Class: MoreMath::ContinuedFraction

Inherits:
Object
  • Object
show all
Defined in:
lib/more_math/continued_fraction.rb

Overview

This class implements a continued fraction of the form:

b_1

a_0 + ————————-

                      b_2
a_1 + --------------------
                      b_3
     a_2 + ---------------
                      b_4
          a_3 + ----------
                      b_5
               a_4 + -----
                      ...

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeContinuedFraction

Creates a continued fraction instance. With the defaults for_a { 1 } and for_b { 1 } it approximates the golden ration phi if evaluated.



21
22
23
24
# File 'lib/more_math/continued_fraction.rb', line 21

def initialize
  @a = proc { 1.0 }
  @b = proc { 1.0 }
end

Class Method Details

.for_a(arg = nil, &block) ⇒ Object

Creates a ContinuedFraction instances and passes its arguments to a call to for_a.



28
29
30
# File 'lib/more_math/continued_fraction.rb', line 28

def self.for_a(arg = nil, &block)
  new.for_a(arg, &block)
end

.for_b(arg = nil, &block) ⇒ Object

Creates a ContinuedFraction instances and passes its arguments to a call to for_b.



34
35
36
# File 'lib/more_math/continued_fraction.rb', line 34

def self.for_b(arg = nil, &block)
  new.for_b(arg, &block)
end

Instance Method Details

#a(n, x = nil) ⇒ Object

Returns the value for a_n or a_n(x).



71
72
73
74
75
76
77
# File 'lib/more_math/continued_fraction.rb', line 71

def a(n, x = nil)
  result = if x
    @a[n, x]
  else
    @a[n]
  end and result.to_f
end

#b(n, x = nil) ⇒ Object

Returns the value for b_n or b_n(x).



80
81
82
83
84
85
86
# File 'lib/more_math/continued_fraction.rb', line 80

def b(n, x = nil)
  result = if x
    @b[n, x]
  else
    @b[n]
  end and result.to_f
end

#call(x = nil, epsilon = 1E-16, max_iterations = 1 << 31) ⇒ Object Also known as: []

Evaluates the continued fraction for the value x (if any) with the accuracy epsilon and max_iterations as the maximum number of iterations using the Wallis-method with scaling.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/more_math/continued_fraction.rb', line 91

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

#for_a(arg = nil, &block) ⇒ Object

This method either takes a block or an argument arg. The argument arg has to respond to an integer index n >= 0 and return the value a_n. The block has to return the value for a_n when n is passed as the first argument to the block. If a_n is dependent on an x value (see the call method) the x will be the second argument of the block.



43
44
45
46
47
48
49
50
51
52
# File 'lib/more_math/continued_fraction.rb', line 43

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

#for_b(arg = nil, &block) ⇒ Object

This method either takes a block or an argument arg. The argument arg has to respond to an integer index n >= 1 and return the value b_n. The block has to return the value for b_n when n is passed as the first argument to the block. If b_n is dependent on an x value (see the call method) the x will be the second argument of the block.



59
60
61
62
63
64
65
66
67
68
# File 'lib/more_math/continued_fraction.rb', line 59

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

#to_procObject

Returns this continued fraction as a Proc object which takes the same arguments like its call method does.



136
137
138
# File 'lib/more_math/continued_fraction.rb', line 136

def to_proc
  proc { |*a| call(*a) }
end