Class: Bullshit::ContinuedFraction

Inherits:
Object
  • Object
show all
Defined in:
lib/bullshit.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.


66
67
68
69
# File 'lib/bullshit.rb', line 66

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.


73
74
75
# File 'lib/bullshit.rb', line 73

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.


79
80
81
# File 'lib/bullshit.rb', line 79

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).


116
117
118
119
120
121
122
# File 'lib/bullshit.rb', line 116

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).


125
126
127
128
129
130
131
# File 'lib/bullshit.rb', line 125

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.


136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/bullshit.rb', line 136

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.


88
89
90
91
92
93
94
95
96
97
# File 'lib/bullshit.rb', line 88

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.


104
105
106
107
108
109
110
111
112
113
# File 'lib/bullshit.rb', line 104

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.


181
182
183
# File 'lib/bullshit.rb', line 181

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