Module: Fibonaccia

Extended by:
BigMath, Enumerable
Includes:
BigMath
Defined in:
lib/fibonaccia/module-doc.rb,
lib/fibonaccia.rb,
lib/fibonaccia/version.rb,
lib/fibonaccia/exceptions.rb

Overview

The Fibonaccia module simply provides three things to Ruby code:

  1. Access to a constant, Fibonaccia.PHI (φ), which is the value of the Golden Ratio (see the Wikipedia article) either to whatever precision Ruby is using, or to an arbitrarily great precision using BigDecimal semantics;

  2. The Fibonacci sequence, to however many terms you desire (and your resources can support);

  3. Coördinates to construct a golden spiral (not the Fibonacci spiral, which is an approximation of the golden spiral). Not yet implemented.

Defined Under Namespace

Modules: ClassMethods Classes: Exception, NotPositiveInteger

Constant Summary collapse

BDPrecision =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

The number of digits of precision we want for our BigDecimal operations.

BigDecimal::double_fig
PHI_Float =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Note:

Use Fibonaccia.PHI or Fibonaccia.PHI(false) to access this value.

Phi (φ), the golden ratio. φ can be simply expressed by a formula, but it’s an irrational number, meaning that the default precision is implementation-specific.

Provide a Float value which uses the default precision.

See Also:

(1.0 + Math.sqrt(5)) / 2.0
PHI =

Default value of φ as a Float.

Referencing PHI as a constant (Fibonaccia::PHI) is equivalent to:

Fibonaccia.PHI(false)

Use PHI(true) to obtain the BigDecimal representation.

calculated_constant
PHI_BigDecimal =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Note:

Use Fibonaccia.PHI(true) to access this value.

Provide a value for φ using an arbitrarily large precision.

See Also:

(1.0 + BigDecimal.new(5).sqrt(BDPrecision)) / 2.0
B_Float =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Constant used to construct a Golden Spiral. See the Wikipedia article for details of its definition and use. This constant is a Float value. For greater precision, use B_BigDecimal.

(2.0 * Math.log(PHI_Float)) / Math::PI
B_BigDecimal =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Constant used to construct a Golden Spiral. See the Wikipedia article for details of its definition and use. This constant is a BigDecimal value. If you don’t need arbitrarily great precision, use B_BigDecimal instead.

((2.0 * BigMath.log(PHI_BigDecimal, BDPrecision)) / BigMath.PI(BDPrecision))
C_Float =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Constant used to construct a Golden Spiral. See the Wikipedia article for details of its definition and use. This constant is a Float value. For greater precision, use B_BigDecimal.

Math.exp(B_Float)
C_BigDecimal =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Constant used to construct a Golden Spiral. See the Wikipedia article for details of its definition and use. This constant is a BigDecimal value. If you don’t need arbitrarily great precision, use B_BigDecimal instead.

BigMath.exp(B_BigDecimal, BDPrecision)
SEED =

First three terms of the Fibonacci sequence, which is our seed and our minimum internal series.

[ 0, 1, 1 ].freeze
MIN_TERMS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Minimum number of terms in the series – the seed values.

SEED.count
SERIES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Array of Fibonacci numbers to however many terms have been evolved. Defined as a constant because the underlying array structure is mutable even for constants, and it’s pre-seeded with the first three terms.

SEED.dup
MINIMUM_RUBY_VERSION =

Minimum version of Ruby we support.

Versionomy.parse('1.9.3')
VERSION =

Frozen string representation of the module version number.

@version.to_s.freeze

Class Method Summary collapse

Class Method Details

.[](first_term, nterms = 1) ⇒ Object

Alias for slice ( q.v.).

This is included because it’s probably more human-readable to find the n-th term of the sequence using the syntax

Fibonaccia[n]

See Also:



522
# File 'lib/fibonaccia.rb', line 522

define_method(:[], self.instance_method(:slice))

.each {|Integer| ... } ⇒ Array<Integer>, Enumerator

Iterate over the current internal series, yielding each value in turn.

Yields:

  • (Integer)

    Each element of the internal series is yielded in turn.

Returns:

  • (Array<Integer>)

    if a block has been passed.

  • (Enumerator)

    when invoked without a block.



411
412
413
414
# File 'lib/fibonaccia.rb', line 411

def each(&block)
  result		= SERIES.each(&block)
  return result
end

.extend_series(nterms) ⇒ void

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.

This method returns an undefined value.

This method is called to extend the SERIES array if necessary.

Parameters:

  • nterms (Integer)

    If the value of this parameter is greater than the number of terms in the SERIES array, new terms are calculated until the series is long enough.



289
290
291
292
293
294
295
296
# File 'lib/fibonaccia.rb', line 289

def extend_series(nterms)
  nterms		= [ 0, nterms.to_i ].max
  n			= [ 0, nterms - self.terms ].max
  n.times do
    SERIES		<< (SERIES[-2] + SERIES[-1])
  end
  return nil
end

.grow(nterms) ⇒ Integer

Extend the internal series by the specified number of terms.

Parameters:

  • nterms (Integer)

    Number of terms by which to grow the internal series.

Returns:

  • (Integer)

    the number of terms in the series after the operation.

Raises:



310
311
312
313
314
315
316
317
# File 'lib/fibonaccia.rb', line 310

def grow(nterms)
  unless (nterms.kind_of?(Integer) && (nterms >= 0))
    msg		= 'argument must be a non-negative integer'
    raise(Fibonaccia::NotPositiveInteger, msg)
  end
  self.extend_series(self.terms + nterms)
  return self.terms
end

.included(klass) ⇒ void

This method returns an undefined value.

Method invoked when a scope does an include Fibonaccia. We simply emit a warning message and do nothing else.

Parameters:

  • klass (Module, Class)

    Object in whose scope the include appeared.



178
179
180
181
182
# File 'lib/fibonaccia.rb', line 178

def included(klass)
  warn("#warning: #{self.name} " +
       'is not intended for use as a mix-in, but it does no harm')
  return nil
end

.is_fibonacci?(val) ⇒ Boolean

See if value appears in the Fibonacci series.

Check to see if the given value is found in the Fibonacci series, using the transform described at https://en.wikipedia.org/wiki/Fibonacci_number#Recognizing_Fibonacci_numbers.

Parameters:

  • val (Integer)

    Value to be checked for membership in the Fibonacci series.

Returns:

  • (Boolean)

    true if the given value is a Fibonacci number, else false.

See Also:



549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
# File 'lib/fibonaccia.rb', line 549

def is_fibonacci?(val)
  #
  # Needs to be an integer.
  #
  return false unless (val.respond_to?(:floor) && (val.floor == val))
  #
  # Needs to be non-negative.
  #
  return false if (val < 0)
  return true if (SERIES.include?(val))
  #
  # Easy checks are done, time for some math-fu.
  #
  val		= BigDecimal.new(val)
  [ +4, -4 ].each do |c|
    eqterm		= 5 * (val**2) + c
    root		= eqterm.sqrt(BDPrecision)
    return true if (root.floor == root)
  end
  return false
end

.lastInteger

Return the last value in the internal series.

This is equivalent to

Fibonaccia[-1]

Returns:

  • (Integer)

    the last term in the internal series.



432
433
434
435
# File 'lib/fibonaccia.rb', line 432

def last
  result		= SERIES.last
  return result
end

.PHI(extended = false) ⇒ Float, BigDecimal

Constant Phi (φ), the golden ratio.

φ can be simply expressed by a formula, but it’s an irrational number, meaning that the default precision is implementation-specific. PHI allows you to access the value either at the implementation precision, or the BigDecimal extended precision.

Examples:

Using conventional ‘constant’ semantics

irb> Fibonaccia::PHI
=> 1.618033988749895
irb> Fibonaccia::PHI(false)
=> 1.618033988749895
irb> Fibonaccia::PHI(true)
=> #<BigDecimal:198e990,'0.1618033988 7498948482 0458683433 33333335E1',54(72)>

Using module method semantics

irb> Fibonaccia.PHI
=> 1.618033988749895
irb> Fibonaccia.PHI(false)
=> 1.618033988749895
irb> Fibonaccia.PHI(true)
=> #<BigDecimal:198e990,'0.1618033988 7498948482 0458683433 33333335E1',54(72)>

Parameters:

  • extended (Boolean) (defaults to: false)

Returns:

  • (Float)

    when extended is false (or at least not a true value).

  • (BigDecimal)

    when extended is true.



219
220
221
222
223
224
# File 'lib/fibonaccia.rb', line 219

def PHI(extended=false)
  result		= (extended \
                       ? PHI_BigDecimal \
                       : PHI_Float)
  return result
end

.resetvoid

This method returns an undefined value.

Reset the internal series to just the seed value.

This can be used to free up memory.



394
395
396
397
# File 'lib/fibonaccia.rb', line 394

def reset
  SERIES.replace(SEED)
  return nil
end

.seriesArray<Integer>

Note:

Since this is a duplicate of the module-internal array, it can have a significant impact on memory usage if the series has been extended to any great length.

Copy of the internal series.

Return a dup of the internal series, to however many terms it has grown.

Examples:

irb> require('fibonaccia')
irb> Fibonaccia.series
=> [0, 1, 1]
irb> Fibonaccia[10]
=> 55
irb> Fibonaccia.series
=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

Returns:

  • (Array<Integer>)

    Returns the list of Fibonacci numbers as far as they’ve been calculated by the module.

See Also:



274
275
276
# File 'lib/fibonaccia.rb', line 274

def series
  return SERIES.dup
end

.shrink(nterms) ⇒ Integer

Note:

The series cannot be shrunk to fewer than the SEED elements.

Shrink the internal series by the specified number of terms.

Parameters:

  • nterms (Integer)

    Number of terms by which to shrink the internal series.

Returns:

  • (Integer)

    the number of terms in the series after the operation.

Raises:



336
337
338
339
340
341
342
343
344
# File 'lib/fibonaccia.rb', line 336

def shrink(nterms)
  unless (nterms.kind_of?(Integer) && (nterms >= 0))
    msg		= 'argument must be a non-negative integer'
    raise(Fibonaccia::NotPositiveInteger, msg)
  end
  nterms		= [ MIN_TERMS, self.terms - nterms ].max
  SERIES.replace(SERIES.take(nterms))
  return self.terms
end

.slice(first_term, nterms = 1) ⇒ Integer, ...

Note:

The internal series is zero-based, which means the first term is numbered 0.

Obtain a slice (see Array#slice) of the Fibonacci series.

The internal series will be extended, if necessary, to include all terms requested.

Parameters:

  • first_term (Integer)

    The first term of the slice from the series.

  • nterms (Integer) (defaults to: 1)

    The number of elements in the slice to be returned.

Returns:

  • (Integer)

    if the result is a valid slice containing only one term (i.e., nterms is 1). Returns the Fibonacci term at the specified (zero-based) position in the sequence.

  • (Array<Integer>)

    if the result is a valid multi-element slice (e.g., nterms is greater than 1). Returns the specified slice.

  • (nil)

    if the slice parameters are not meaningful (e.g., slice(1, -1)).

Raises:

  • (ArgumentError)

    if the arguments are not all integers.



465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
# File 'lib/fibonaccia.rb', line 465

def slice(first_term, nterms=1)
  args		= {
    'first_term'	=> first_term,
    'nterms'	=> nterms,
  }
  #
  # Sanity-check our arguments; be more informative than the default
  #
  #    TypeError: no implicit conversion of <class> into Integer
  #
  args.each do |argname,argval|
    unless (argval.kind_of?(Integer))
      raise(ArgumentError, "#{argname} must be an integer")
    end
  end
  nterms		= [ 1, nterms ].max
  if (first_term < 0)
    endpoint	= [ 0, self.terms + first_term + nterms ].max
  else
    endpoint	= first_term + nterms
  end
  Fibonaccia.extend_series(endpoint)
  #
  # We're going to pass this along to the array's own #slice
  # method, so build its argument list appropriately.
  #
  args		= [ first_term ]
  args		<< nterms unless (nterms == 1)
  result		= SERIES.slice(*args)
  #
  # If we got a multi-element slice, make sure we don't return our
  # master sequence!  Ruby shouldn't let it happen, but defensive
  # programing is all.
  #
  result		= result.dup if (result === SERIES)
  return result
end

.termsInteger

The number of terms in the internal series.

Similar to the #count method provided by the Enumerable mix-in, but a more direct approach – and complementary to the terms= method.

Returns:

  • (Integer)

    number of terms in the internal series.



356
357
358
359
# File 'lib/fibonaccia.rb', line 356

def terms
  result		= SERIES.count
  return result
end

.terms=(nterms) ⇒ Integer

Note:

The series cannot be shrunk to fewer than the SEED elements.

Set the internal series to a specific number of terms.

Parameters:

  • nterms (Integer)

    Number of terms to which the series should be grown or shrunk.

Returns:

  • (Integer)

    the number of terms in the series after the operation.

Raises:



373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/fibonaccia.rb', line 373

def terms=(nterms)
  unless (nterms.kind_of?(Integer) && (nterms >= 0))
    msg		= 'argument must be a non-negative integer'
    raise(Fibonaccia::NotPositiveInteger, msg)
  end
  nterms		= [ MIN_TERMS, nterms ].max
  if (nterms > self.terms)
    self.grow(nterms - self.terms)
  elsif (nterms < self.terms)
    self.shrink(self.terms - nterms)
  end
  return self.terms
end

.versionVersionomy

Returns the Versionomy representation of the package version number.

Returns:

  • (Versionomy)


72
73
74
# File 'lib/fibonaccia/version.rb', line 72

def self.version
  return @version
end

.VERSIONString

Returns the package version number as a string.

Returns:

  • (String)

    Package version number.



82
83
84
# File 'lib/fibonaccia/version.rb', line 82

def self.VERSION
  return self.const_get('VERSION')
end