Class: MoreMath::ContinuedFraction
- Includes:
- Enumerable
- Defined in:
- lib/more_math/continued_fraction.rb
Overview
A continued fraction implementation that supports both simple and generalized continued fractions.
Continued fractions are represented in the form:
a₀ + b₁ / (a₁ + b₂ / (a₂ + b₃ / (a₃ + ...)))
For simple continued fractions, all ‘b` coefficients default to 1, and only `a` coefficients vary.
Constant Summary collapse
- SIMPLE_B =
Default b coefficient generator (returns 1 for all indices)
proc { 1 }
Class Method Summary collapse
-
.for_a(arg = nil) {|index| ... } ⇒ ContinuedFraction
Creates a continued fraction instance and sets its ‘a` coefficients.
-
.for_b(arg = nil) {|index| ... } ⇒ ContinuedFraction
Creates a continued fraction instance and sets its ‘b` coefficients.
-
.from(number) ⇒ ContinuedFraction
Creates a continued fraction from a Rational number.
Instance Method Summary collapse
-
#a(n, x = nil) ⇒ Object
private
private
Returns the value for a_n or a_n(x).
-
#b(n, x = nil) ⇒ Object
private
private
Returns the value for b_n or b_n(x).
-
#call(x = nil, epsilon: 1E-16, max_iterations: 1 << 31) ⇒ Float
(also: #[], #to_f)
Evaluates the continued fraction for a given value ‘x`.
-
#each {|convergent| ... } ⇒ Object
Iterates over convergents of this continued fraction (only for simple fractions).
-
#for_a(arg = nil) {|index| ... } ⇒ ContinuedFraction
Sets the ‘a` coefficients for this continued fraction.
-
#for_arg(arg = nil, &block) ⇒ Object
private
private
Helper method to validate and process arguments for ‘for_a` and `for_b`.
-
#for_b(arg = nil) {|index| ... } ⇒ ContinuedFraction
Sets the ‘b` coefficients for this continued fraction.
-
#initialize ⇒ ContinuedFraction
constructor
Creates a new continued fraction with default coefficients.
-
#inspect ⇒ String
Returns a string representation of the continued fraction.
-
#reciprocal ⇒ ContinuedFraction
Returns the reciprocal of this continued fraction.
-
#simple? ⇒ Boolean
Checks if this is a simple continued fraction (all ‘b` coefficients are 1).
-
#to_proc ⇒ Proc
Converts this continued fraction into a Proc that can be called directly.
-
#to_s(length: 10) ⇒ String
Returns a string representation of the continued fraction.
-
#value(v, n, x = nil) ⇒ Object
private
private
Helper method for retrieving coefficient values, supporting both indexed access and block evaluation.
Constructor Details
#initialize ⇒ ContinuedFraction
Creates a new continued fraction with default coefficients. The defaults for ‘a` and `b` are both set to 1, which approximates the golden ratio when evaluated.
40 41 42 43 |
# File 'lib/more_math/continued_fraction.rb', line 40 def initialize @a = proc { 1 } @b = SIMPLE_B end |
Class Method Details
.for_a(arg = nil) {|index| ... } ⇒ ContinuedFraction
Creates a continued fraction instance and sets its ‘a` coefficients. This is a class method for convenience when building continued fractions.
58 59 60 |
# File 'lib/more_math/continued_fraction.rb', line 58 def self.for_a(arg = nil, &block) new.for_a(arg, &block) end |
.for_b(arg = nil) {|index| ... } ⇒ ContinuedFraction
Creates a continued fraction instance and sets its ‘b` coefficients. This is a class method for convenience when building continued fractions.
75 76 77 |
# File 'lib/more_math/continued_fraction.rb', line 75 def self.for_b(arg = nil, &block) new.for_b(arg, &block) end |
.from(number) ⇒ ContinuedFraction
Creates a continued fraction from a Rational number.
100 101 102 103 104 105 106 107 108 109 |
# File 'lib/more_math/continued_fraction.rb', line 100 def self.from(number) number = number.to_r n, d = number.numerator, number.denominator as = [] while d > 0 n, (a, d) = d, n.divmod(d) as << a end for_a(as) end |
Instance Method Details
#a(n, x = nil) ⇒ Object (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the value for a_n or a_n(x).
284 285 286 |
# File 'lib/more_math/continued_fraction.rb', line 284 def a(n, x = nil) value(@a, n, x) end |
#b(n, x = nil) ⇒ Object (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the value for b_n or b_n(x).
291 292 293 |
# File 'lib/more_math/continued_fraction.rb', line 291 def b(n, x = nil) value(@b, n, x) end |
#call(x = nil, epsilon: 1E-16, max_iterations: 1 << 31) ⇒ Float Also known as: [], to_f
Evaluates the continued fraction for a given value ‘x`.
For generalized continued fractions, the coefficients may depend on an external parameter ‘x`. The Wallis method with scaling is used for convergence.
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/more_math/continued_fraction.rb', line 203 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 |
#each {|convergent| ... } ⇒ Object
Iterates over convergents of this continued fraction (only for simple fractions).
179 180 181 182 183 |
# File 'lib/more_math/continued_fraction.rb', line 179 def each(&block) if simple? (0..Float::INFINITY).lazy.map { |i| @a[i] }.take_while { |x| x }.each(&block) end end |
#for_a(arg = nil) {|index| ... } ⇒ ContinuedFraction
Sets the ‘a` coefficients for this continued fraction.
123 124 125 126 |
# File 'lib/more_math/continued_fraction.rb', line 123 def for_a(arg = nil, &block) @a = for_arg(arg, &block) self end |
#for_arg(arg = nil, &block) ⇒ Object (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Helper method to validate and process arguments for ‘for_a` and `for_b`.
82 83 84 85 86 87 88 89 90 |
# File 'lib/more_math/continued_fraction.rb', line 82 def for_arg(arg = nil, &block) if arg && !block arg.freeze elsif block && !arg block else raise ArgumentError, "exactly one argument or one block required" end end |
#for_b(arg = nil) {|index| ... } ⇒ ContinuedFraction
Sets the ‘b` coefficients for this continued fraction.
140 141 142 143 |
# File 'lib/more_math/continued_fraction.rb', line 140 def for_b(arg = nil, &block) @b = for_arg(arg, &block) self end |
#inspect ⇒ String
Returns a string representation of the continued fraction.
168 169 170 |
# File 'lib/more_math/continued_fraction.rb', line 168 def inspect "#<#{self.class} #{to_s}>" end |
#reciprocal ⇒ ContinuedFraction
Returns the reciprocal of this continued fraction.
247 248 249 250 251 252 253 |
# File 'lib/more_math/continued_fraction.rb', line 247 def reciprocal if @a[0] > 0 dup.for_a { |i| i == 0 ? 0 : @a[i - 1] } else dup.for_a { |i| @a[i + 1] } end end |
#simple? ⇒ Boolean
Checks if this is a simple continued fraction (all ‘b` coefficients are 1).
148 149 150 |
# File 'lib/more_math/continued_fraction.rb', line 148 def simple? @b == SIMPLE_B end |
#to_proc ⇒ Proc
Converts this continued fraction into a Proc that can be called directly.
264 265 266 |
# File 'lib/more_math/continued_fraction.rb', line 264 def to_proc proc { |*a| call(*a) } end |
#to_s(length: 10) ⇒ String
Returns a string representation of the continued fraction.
156 157 158 159 160 161 162 163 |
# File 'lib/more_math/continued_fraction.rb', line 156 def to_s(length: 10) if simple? convergents = take(length) "[#{convergents[0]}; #{convergents[1..-1] * ', '}#{",…" if convergents.size >= length}]" else "CF(a=#@a, b=#@b)" end end |
#value(v, n, x = nil) ⇒ Object (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Helper method for retrieving coefficient values, supporting both indexed access and block evaluation.
273 274 275 276 277 278 279 |
# File 'lib/more_math/continued_fraction.rb', line 273 def value(v, n, x = nil) result = if x v[n, x] else v[n] end and result.to_f end |