LoginSignup
2
0

More than 3 years have passed since last update.

[Ruby] 無限フィボナッチ

Last updated at Posted at 2019-11-28

無限フィボナッチ

Yo! クリぼっちでも フィボナッチ:sunglasses:

旧コード

大好きな DelegateClass と Enumerator を組み合わせて書いてみた。後で書き直しました (後述) 。

class FibonacciNumbers < DelegateClass(Enumerator)
  def initialize
    super(fibonacci_numbers)
  end

  private

  def fibonacci_numbers
    Enumerator.new do |y|
      memo = [0, 1]

      loop.with_index do |_, i|
        if i < 2
          y << memo[i]
        else
          memo = memo[1], memo.sum
          y << memo[1]
        end
      end
    end
  end
end

fibonacci_numbers = FibonacciNumbers.new
fibonacci_numbers.first(10) #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
fibonacci_numbers.first(10_000).last #=> 20793608237133498072112648988642836825087036094015903119682945866528501423455686648927456034305226515591757343297190158010624794267250973176133810179902738038231789748346235556483191431591924532394420028067810320408724414693462849062668387083308048250920654493340878733226377580847446324873797603734794648258113858631550404081017260381202919943892370942852601647398213554479081823593715429566945149312993664846779090437799284773675379284270660175134664833266377698642012106891355791141872776934080803504956794094648292880566056364718187662668970758537383352677420835574155945658542003634765324541006121012446785689171494803262408602693091211601973938229446636049901531963286159699077880427720289235539329671877182915643419079186525118678856821600897520171070499437657067342400871083908811800976259727431820539554256869460815355918458253398234382360435762759823179896116748424269545924633204614137992850814352018738480923581553988990897151469406131695614497783720743461373756218685106856826090696339815490921253714537241866911604250597353747823733268178182198509240226955826416016690084749816072843582488613184829905383150180047844353751554201573833105521980998123833253261228689824051777846588461079790807828367132384798451794011076569057522158680378961532160858387223882974380483931929541222100800313580688585002598879566463221427820448492565073106595808837401648996423563386109782045634122467872921845606409174360635618216883812562321664442822952537577492715365321134204530686742435454505103269768144370118494906390254934942358904031509877369722437053383165360388595116980245927935225901537634925654872380877183008301074569444002426436414756905094535072804764684492105680024739914490555904391369218696387092918189246157103450387050229300603241611410707453960080170928277951834763216705242485820801423866526633816082921442883095463259080471819329201710147828025221385656340207489796317663278872207607791034431700112753558813478888727503825389066823098683355695718137867882982111710796422706778536913192342733364556727928018953989153106047379741280794091639429908796650294603536651238230626

なお

def fibonacci_numbers
  memo = [0, 1]

  Enumerator.new do |y|
    # 略
  end
end

と、ローカル変数 memo の代入を Enumerator.new のブロックの外で行うと挙動が変わってしまうので注意。

# Enumerator.new のブロックがクロージャとしてローカル変数 memo の状態を保持してしまう。
# そのせいで first に 3 以上の整数を渡して呼び出すと、つど結果が変わってしまう。
fibonacci_numbers.first(3) #=> [0, 1, 1]
fibonacci_numbers.first(3) #=> [1, 1, 2]
fibonacci_numbers.first(3) #=> [1, 2, 3]

新コード

@kts_h さんのコメントを参考 (というかほぼそのままですが……) にして、以下の方針でよりシンプルなコードにしました。

  • オブジェクトを生成せずに FibonacciNumbers の Module 自体に機能をもたせる。
  • 他のオブジェクトに委譲するのではなく FibonacciNumbers 自体を Enumerable にする。
  • loop メソッドのブロック内の if 式を取り除く。
module FibonacciNumbers
  extend Enumerable

  def self.each
    return enum_for unless block_given?

    a, b = 0, 1
    loop do
      yield a
      a, b = b, a + b
    end
  end
end

FibonacciNumbers.first(10) #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
FibonacciNumbers.first(10_000).last #=> 20793608237133498072112648988642836825087036094015903119682945866528501423455686648927456034305226515591757343297190158010624794267250973176133810179902738038231789748346235556483191431591924532394420028067810320408724414693462849062668387083308048250920654493340878733226377580847446324873797603734794648258113858631550404081017260381202919943892370942852601647398213554479081823593715429566945149312993664846779090437799284773675379284270660175134664833266377698642012106891355791141872776934080803504956794094648292880566056364718187662668970758537383352677420835574155945658542003634765324541006121012446785689171494803262408602693091211601973938229446636049901531963286159699077880427720289235539329671877182915643419079186525118678856821600897520171070499437657067342400871083908811800976259727431820539554256869460815355918458253398234382360435762759823179896116748424269545924633204614137992850814352018738480923581553988990897151469406131695614497783720743461373756218685106856826090696339815490921253714537241866911604250597353747823733268178182198509240226955826416016690084749816072843582488613184829905383150180047844353751554201573833105521980998123833253261228689824051777846588461079790807828367132384798451794011076569057522158680378961532160858387223882974380483931929541222100800313580688585002598879566463221427820448492565073106595808837401648996423563386109782045634122467872921845606409174360635618216883812562321664442822952537577492715365321134204530686742435454505103269768144370118494906390254934942358904031509877369722437053383165360388595116980245927935225901537634925654872380877183008301074569444002426436414756905094535072804764684492105680024739914490555904391369218696387092918189246157103450387050229300603241611410707453960080170928277951834763216705242485820801423866526633816082921442883095463259080471819329201710147828025221385656340207489796317663278872207607791034431700112753558813478888727503825389066823098683355695718137867882982111710796422706778536913192342733364556727928018953989153106047379741280794091639429908796650294603536651238230626

これまでに試した似たやつ

2
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0