SlideShare a Scribd company logo
1 of 17
Download to read offline
フィボナッチ数列の作り方
2013/2/2
cuzic
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
自己紹介
最近のできごと
Dell XPS 12 を買いました。
不思議なギミックでタブレットになる
Full HD、Touch Panel、Display Portポート
Office 365 Home Premium に契約しました
毎月 $9.99 で Office の最新版を利用可能
パワポ、エクセル、ワードを最大5台にインストール可能
(2013年2月2日現在)日本では、まだサービス開始していません。。。
今後の勉強会
プログラマのためのサバイバルマニュアル読書会 第1回
3月2日 JR尼崎駅 徒歩2分 小田公民館で開催
11
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
22フィボナッチ数列について
次の漸化式を満たす数列をフィボナッチ数列という
フィボナッチ数列の特徴
うさぎの増え方を表現する漸化式
𝐹𝑛−1
𝐹𝑛
が 黄金比(
5−1
2
= 0.683 …) に収束する
プログラミングにおけるフィボナッチ数列
関数型プログラミング言語における Hello, World!
入門向けに使える程度の複雑さ
切り口によって、いろんな説明ができる
今回は、フィボナッチ数列の求め方をいろいろ説明します。
𝑭 𝒏 =
𝟎
𝟏
𝑭 𝒏−𝟏 + 𝑭 𝒏−𝟐
𝒏 = 𝟎
𝒏 = 𝟏
𝒏 ≥ 𝟐
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
単純な実装 33
a = 0; b = 1
loop do
a, b = b, a + b
break if 100 < a
puts a
end
■ (1) もっとも単純な実装 ■ (2) 多重代入の利用
もっとも単純なフィボナッチ数列の Ruby による実装
ポイント: ループ、多重代入、while の構文
a = 0; b = 1
loop do
tmp = a
a = b
b = tmp + b
break if 100 < a
puts a
end
a = 0; b = 1
while a < 100
puts b
a, b = b, a + b
end
■ (3) while の利用
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
ブロック付メソッド 44
■ (4) ブロック付メソッド呼び出し ■ 処理の実施順
yield キーワードにより、ブロック引数に値を渡せる。
ブロック付メソッド呼出しにより、
値の生成と、値の利用の処理を分離できる
def fibonacci
a = 0; b = 1
loop do
a, b = b, a + b
yield a
end
end
n = 1
fibonacci do |i|
break if 100 < a
puts “#{n} #{i}"
n += 1
end
①
②
③
⑤
⑦
⑤ → ①
→ ② → ⑦ → ③
→ ② → ⑦ → ③
→ ② → ⑦ → ③
・・・ (以下おなじ)
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
クラスの利用 55
■ (5) クラスの利用
クラスを利用し、内部状態をインスタンス変数に持たせる方法もある
この場合は、next を実行したときに内部状態が変化する。
class Fibonacci
def initialize
@a = 0; @b = 1
end
def next
@a, @b = @b, @a + @b
return @a
end
end
fibonacci = Fibonacci.new
loop do
i = fibonacci.next()
break if i > 100
puts i
end
インスタンス変数の初期化インスタンス変数の初期化
次の値の生成次の値の生成
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
クロージャ 66
■ (6) クロージャの利用
クロージャという機能により、ブロックの中から
ネストの外側の変数を参照できる。
内部状態を持つ関数を簡易に作ることができる。
fibonacci = proc do
a = 0; b = 1
lambda do
a, b = b, a + b
return a
end
end.call()
loop do
i = fibonacci.()
break if i > 100
puts i
end
スコープを導入するためのクロージャスコープを導入するためのクロージャ
外側のクロージャを呼ぶ出すための Proc#call外側のクロージャを呼ぶ出すための Proc#call
内側のクロージャを作るための lambda
中で return を使いたいので 「 lambda 」にしている。
内側のクロージャを作るための lambda
中で return を使いたいので 「 lambda 」にしている。
クロージャを呼び出し、Fibonacci 数列の次の値を取得するクロージャを呼び出し、Fibonacci 数列の次の値を取得する
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
Ruby 1.8: Generator の利用 77
■ (7) Generator の利用
Ruby 1.8 には、標準ライブラリに Generator があった
内部実装に callcc を使うので、ちょいと遅い
require 'generator'
g = Generator.new do |yielder|
a = 0; b = 1
loop do
a, b = b, a + b
yielder.yield a
end
end
g.each do |i|
break if i > 100
puts i
end
Generator が生成する項を順に取得するGenerator が生成する項を順に取得する
次の値を生成する次の値を生成する
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
Ruby 1.9: Enumerator の利用 88
■ (8) Enumerator の利用
Ruby 1.9 では Enumerator を利用可能
内部実装に Fiber を使うため、高速
Enumerable モジュールのメソッド(each_cons など)を利用可能
e = Enumerator.new do |yielder|
a = 0; b = 1
loop do
a, b = b, a + b
yielder << a
end
end
e.each do |i|
break if i > 100
puts i
end
Enumerator が生成する項を順に取得するEnumerator が生成する項を順に取得する
次の生成する値を yield する次の生成する値を yield する
Enumerator による実装は、
利用側のコード行数がコンパクト
になる。
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
(参考) Enumerator と Fiber 99
e = Enumerator.new do |yielder|
a = 0; b = 1
loop do
a, b = b, a + b
yielder << a
end
end
e.each do |i|
break if 100 < i
puts i
end
■ (8) 《再掲》 Enumerator の例
fib = Fiber.new do
a = 0; b = 1
loop do
a, b = b, a + b
Fiber.yield a
end
end
def fib.each
loop do
yield self.resume
end
end
fib.each do |i|
break if 100 > i
puts i
end
■ 《参考》 (9) Fiberの例
Enumerator は Fiber を活用するデザインパターンの1つ
Fiber における難しい概念を隠ぺい
Fiber.yield => Enumerator::Yielder#<< 、 Enumerator#each による列挙
Enumerator を使いこなせれば、十分 Fiber のメリットを活用できる
《参考: Fiber にできて、Enumerator でできないこと》
親 Fiber から 子Fiber へのデータの送付(Fiber.yield の返り値の利用)
これが必要。
だけど、これが
難しい。(汗)
Enumerator の
内部実装まで
考えなくていい
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
Enumerator はベンリ 1010
fib = Enumerator.new do |yielder|
a = 0; b = 1
loop do
a, b = b, a + b
yielder << a
end
end
fib.each do |i|
break if 100 < I
puts i
end
fib.each_cons(2) do |i, j|
break if 100 < i
puts "#{i} #{j}"
end
■ (10) Enumerator の例
def fibonacci
a = 0; b = 1
loop do
a, b = b, a + b
yield a
end
end
fibonacci do |i|
break if 100 < i
puts i
end
prev = nil
fibonacci do |i|
break if 100 < i
puts "#{prev} #{i}" if prev
prev = i
end
■ 《参考》 (11) ブロック付メソッド呼び出しの例
Enumerator なら Enumerable の便利メソッドを使える。
ブロック付メソッド呼び出しは単純なイテレーションならいいけど。。。
Enumerator はオブジェクトなので、使い回しが簡単。
引数にしたり、返り値にしたり、インスタンス変数に格納したり
Enumerator オブジェクトの生成も慣れれば簡単。
慣れれば、
カンタン
面倒 ! !
Enumerable
の便利メソッド
を使い放題
単純なイテレーション
ならいいけど・・・。
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
Enumerable#lazy の利用 1111
fib = Enumerator.new do |yielder|
a = 0; b = 1
loop do
a, b = b, a + b
yielder << a
end
end
fib.select do |i|
i < 100
end.
take(10).each do |i|
puts i
end
■ (12) うまく動かない例
fib = Enumerator.new do |yielder|
a = 0; b = 1
loop do
a, b = b, a + b
yielder << a
end
end
fib.lazy.select do |i|
i < 100
end.take(10).each do |i|
puts i
end
■ (13) Enumerable#lazy を利用する例
Ruby 2.0.0 から、Enumerable#lazy が利用可能となる
Enumerable#lazy を使うと、遅延評価になり、無限を無限のまま扱える
宇宙ヤバい
Ruby 1.9 でも gem でインストール可能
@yhara さんの作品
ここで、無限ループに
なり、うまく動かない。
※ take_while を
使う方法もある。
Enumerable#lazy
を使えば、正しく
期待通りに動作する
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
(参考)Enumerable#lazy の実装(Ruby 2.0 での実際の実装とは異なる) 1212
module Enumerable
def lazy
Enumerator::Lazy.new(self)
end
end
class Enumerator
class Lazy < Enumerator
def initialize(obj, &block)
super(){|yielder|
begin
obj.each{|x|
if block
block.call(yielder, x)
else
yielder << x
end
}
rescue StopIteration
end
}
end
def select(&block)
Lazy.new(self){|yielder, val|
if block.call(val)
yielder << val
end
}
end
def take(n)
taken = 0
Lazy.new(self){|yielder, val|
if taken < n
yielder << val
taken += 1
else
raise StopIteration
end
}
end
……
end
Enumerable#lazy を使うと、Enumerable のメソッドの返り値が
Enumerator::Lazy オブジェクトになる
Enumerable モジュールに増やすメソッドは Enumerable#lazy だけ
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
単純な再帰と末尾再帰
フィボナッチ数列を再帰で求めてみる
関数型プログラミング言語の入門には、ほぼ必ず登場する例
適度な難易度で説明しやすい
末尾再帰による高速化、遅延評価とかを説明できる
1313
# めちゃくちゃ速い : O(n) の速さ
def fib n, a = 0, b = 1
return a if n == 0
return fib(n-1, b, a+b)
end
# def fib_nonrecursive n
# a = 0; b = 1
# loop do
# return a if n == 0
# n, a, b = n-1, b, a+b
# end
# end
(0..30).each do |n|
puts fib(n)
end
# めちゃくちゃ遅い (指数関数オーダ)
def fib n
return n if n <= 1
return fib(n-1) + fib(n-2)
end
(0..30).each do |n|
puts fib(n)
end
■ (14) 単純な再帰、n項を取得 ■ (15) 再帰の例(高速版)
末尾再帰のコードと
まったく同じ処理を
再帰を使わずに
書くとこうなる。
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
再帰と memoize
memoize という高速化手法がある
最初の一度だけ計算し、2回目以降は前回計算済みの値を返す
メモリを多く消費するが、計算時間を短縮できる
同じ計算を繰り返すときは、コストに見合う高速化効果が得られる
遅い再帰でも memoize することで、大幅に高速化できる
1414
# memoize版。同じ計算は1度だけ。圧倒的に速い。
def add a, b
memo = nil
lambda do
return memo if memo
memo = a.() + b.()
return memo
end
end
fib = Enumerator.new do |yielder|
a = lambda{ 0 }
b = lambda{ 1 }
loop do
a, b = b, add(a, b)
yielder << a
end
end
fib.take(36).each do |i|
puts i.()
end
# memoize しない場合。同じ計算を何度もする。
# すごい遅い。
def add a, b
lambda do
return a.() + b.()
end
end
fib = Enumerator.new do |yielder|
a = lambda{ 0 }
b = lambda{ 1 }
loop do
a, b = b, add(a, b)
yielder << a
end
end
fib.take(36).each do |i|
puts i.()
end
■ (16) memoize しない例 ■ (17) memoize する例
2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」
1515まとめ
単純な問題だけど、いろんな解法がある
ループ、ブロック付メソッド、クラス、クロージャ、
Enumerator、再帰
個人的オススメは、Enumerator による実装
利用側のコードがコンパクト
Enumerable モジュールの便利メソッドが使える
Enumerable#lazy とか
再帰はとくに実装がコンパクトになる
ただし、注意しないと非常に遅い実装になることもある
遅いときも下記の指針に従うことで、高速化できる。
更新が必要な内部状態を引数に持ってくるように引数を見直す
memoize を使って、計算を一度だけにする。
1616
ご清聴ありがとう
ございました

More Related Content

Similar to フィボナッチ数列の作り方

Enumerable lazy について
Enumerable lazy についてEnumerable lazy について
Enumerable lazy についてTomoya Kawanishi
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回Tomoya Kawanishi
 
18166746-NeverBlock-RubyKaigi2009
18166746-NeverBlock-RubyKaigi200918166746-NeverBlock-RubyKaigi2009
18166746-NeverBlock-RubyKaigi2009Muhammad Ali
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)啓 小笠原
 
Ruby&Active Support for expert 3
Ruby&Active Support for expert 3Ruby&Active Support for expert 3
Ruby&Active Support for expert 3xibbar
 
怠惰なRubyistへの道 fukuoka rubykaigi01
怠惰なRubyistへの道 fukuoka rubykaigi01怠惰なRubyistへの道 fukuoka rubykaigi01
怠惰なRubyistへの道 fukuoka rubykaigi01nagachika t
 
Ansible troubleshooting 101_2021
Ansible troubleshooting 101_2021Ansible troubleshooting 101_2021
Ansible troubleshooting 101_2021Hideki Saito
 
Cookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
Cookpad 17 day Tech internship 2017 言語処理系入門 RubyをコンパイルしようCookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
Cookpad 17 day Tech internship 2017 言語処理系入門 RubyをコンパイルしようKoichi Sasada
 
メタメタプログラミングRuby
メタメタプログラミングRubyメタメタプログラミングRuby
メタメタプログラミングRubyemasaka
 
Swiftによる関数型プログラミング超入門
Swiftによる関数型プログラミング超入門Swiftによる関数型プログラミング超入門
Swiftによる関数型プログラミング超入門Hisakuni Fujimoto
 
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーmganeko
 
ffi for rubyists
ffi for rubyistsffi for rubyists
ffi for rubyistsnanki
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogrammingMasanori Kado
 
Start!! Ruby
Start!! RubyStart!! Ruby
Start!! Rubymitim
 
Ruby on Rails 入門
Ruby on Rails 入門Ruby on Rails 入門
Ruby on Rails 入門Yasuko Ohba
 
Polyphony: Python ではじめる FPGA
Polyphony: Python ではじめる FPGAPolyphony: Python ではじめる FPGA
Polyphony: Python ではじめる FPGAryos36
 
Swift を振り返ってみよう #cswift
Swift を振り返ってみよう #cswiftSwift を振り返ってみよう #cswift
Swift を振り返ってみよう #cswiftTomohiro Kumagai
 
Ruby1.9のfiberのかっこよくつかおう
Ruby1.9のfiberのかっこよくつかおうRuby1.9のfiberのかっこよくつかおう
Ruby1.9のfiberのかっこよくつかおうKindai University
 

Similar to フィボナッチ数列の作り方 (20)

Fiberの使いどころ
Fiberの使いどころFiberの使いどころ
Fiberの使いどころ
 
Enumerable lazy について
Enumerable lazy についてEnumerable lazy について
Enumerable lazy について
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回
 
18166746-NeverBlock-RubyKaigi2009
18166746-NeverBlock-RubyKaigi200918166746-NeverBlock-RubyKaigi2009
18166746-NeverBlock-RubyKaigi2009
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
 
Ruby&Active Support for expert 3
Ruby&Active Support for expert 3Ruby&Active Support for expert 3
Ruby&Active Support for expert 3
 
怠惰なRubyistへの道 fukuoka rubykaigi01
怠惰なRubyistへの道 fukuoka rubykaigi01怠惰なRubyistへの道 fukuoka rubykaigi01
怠惰なRubyistへの道 fukuoka rubykaigi01
 
Ansible troubleshooting 101_2021
Ansible troubleshooting 101_2021Ansible troubleshooting 101_2021
Ansible troubleshooting 101_2021
 
Cookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
Cookpad 17 day Tech internship 2017 言語処理系入門 RubyをコンパイルしようCookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
Cookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
 
メタメタプログラミングRuby
メタメタプログラミングRubyメタメタプログラミングRuby
メタメタプログラミングRuby
 
Swiftによる関数型プログラミング超入門
Swiftによる関数型プログラミング超入門Swiftによる関数型プログラミング超入門
Swiftによる関数型プログラミング超入門
 
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
 
ffi for rubyists
ffi for rubyistsffi for rubyists
ffi for rubyists
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogramming
 
Node.js入門
Node.js入門Node.js入門
Node.js入門
 
Start!! Ruby
Start!! RubyStart!! Ruby
Start!! Ruby
 
Ruby on Rails 入門
Ruby on Rails 入門Ruby on Rails 入門
Ruby on Rails 入門
 
Polyphony: Python ではじめる FPGA
Polyphony: Python ではじめる FPGAPolyphony: Python ではじめる FPGA
Polyphony: Python ではじめる FPGA
 
Swift を振り返ってみよう #cswift
Swift を振り返ってみよう #cswiftSwift を振り返ってみよう #cswift
Swift を振り返ってみよう #cswift
 
Ruby1.9のfiberのかっこよくつかおう
Ruby1.9のfiberのかっこよくつかおうRuby1.9のfiberのかっこよくつかおう
Ruby1.9のfiberのかっこよくつかおう
 

More from Tomoya Kawanishi

ENECHANGE社での Scout APM 利用事例
ENECHANGE社での Scout APM 利用事例ENECHANGE社での Scout APM 利用事例
ENECHANGE社での Scout APM 利用事例Tomoya Kawanishi
 
エンジニア転職のノウハウ
エンジニア転職のノウハウエンジニア転職のノウハウ
エンジニア転職のノウハウTomoya Kawanishi
 
Ruby の文字列について
Ruby の文字列についてRuby の文字列について
Ruby の文字列についてTomoya Kawanishi
 
Ruby on Rails のキャッシュ機構について
Ruby on Rails のキャッシュ機構についてRuby on Rails のキャッシュ機構について
Ruby on Rails のキャッシュ機構についてTomoya Kawanishi
 
Ruby初心者からよく質問されること
Ruby初心者からよく質問されることRuby初心者からよく質問されること
Ruby初心者からよく質問されることTomoya Kawanishi
 
RubyGems と Bundler について
RubyGems と Bundler についてRubyGems と Bundler について
RubyGems と Bundler についてTomoya Kawanishi
 
Ruby の正規表現について
Ruby の正規表現についてRuby の正規表現について
Ruby の正規表現についてTomoya Kawanishi
 
Ruby での外部コマンドの実行について
Ruby での外部コマンドの実行についてRuby での外部コマンドの実行について
Ruby での外部コマンドの実行についてTomoya Kawanishi
 
Ruby のワンライナーについて
Ruby のワンライナーについてRuby のワンライナーについて
Ruby のワンライナーについてTomoya Kawanishi
 
AWS のコスト管理をちゃんとしたくてやったこと
AWS のコスト管理をちゃんとしたくてやったことAWS のコスト管理をちゃんとしたくてやったこと
AWS のコスト管理をちゃんとしたくてやったことTomoya Kawanishi
 
PostgreSQL のイケてるテクニック7選
PostgreSQL のイケてるテクニック7選PostgreSQL のイケてるテクニック7選
PostgreSQL のイケてるテクニック7選Tomoya Kawanishi
 
HTTPと Webクローリングについて
HTTPと WebクローリングについてHTTPと Webクローリングについて
HTTPと WebクローリングについてTomoya Kawanishi
 
Active record query interface
Active record query interfaceActive record query interface
Active record query interfaceTomoya Kawanishi
 
Active Support のコア拡張機能について
Active Support のコア拡張機能についてActive Support のコア拡張機能について
Active Support のコア拡張機能についてTomoya Kawanishi
 
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナー
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナーRuby ビジネス創出展 Ruby初心者向けプログラミングセミナー
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナーTomoya Kawanishi
 
RubyのDir、File、IO について
RubyのDir、File、IO についてRubyのDir、File、IO について
RubyのDir、File、IO についてTomoya Kawanishi
 
Thread の利用事例紹介
Thread の利用事例紹介Thread の利用事例紹介
Thread の利用事例紹介Tomoya Kawanishi
 
Ruby の制御構造とリテラルについて
Ruby の制御構造とリテラルについてRuby の制御構造とリテラルについて
Ruby の制御構造とリテラルについてTomoya Kawanishi
 

More from Tomoya Kawanishi (20)

英単語の覚え方
英単語の覚え方英単語の覚え方
英単語の覚え方
 
ENECHANGE社での Scout APM 利用事例
ENECHANGE社での Scout APM 利用事例ENECHANGE社での Scout APM 利用事例
ENECHANGE社での Scout APM 利用事例
 
エンジニア転職のノウハウ
エンジニア転職のノウハウエンジニア転職のノウハウ
エンジニア転職のノウハウ
 
Ruby の文字列について
Ruby の文字列についてRuby の文字列について
Ruby の文字列について
 
Ruby on Rails のキャッシュ機構について
Ruby on Rails のキャッシュ機構についてRuby on Rails のキャッシュ機構について
Ruby on Rails のキャッシュ機構について
 
Ruby初心者からよく質問されること
Ruby初心者からよく質問されることRuby初心者からよく質問されること
Ruby初心者からよく質問されること
 
RubyGems と Bundler について
RubyGems と Bundler についてRubyGems と Bundler について
RubyGems と Bundler について
 
Ruby の正規表現について
Ruby の正規表現についてRuby の正規表現について
Ruby の正規表現について
 
Ruby での外部コマンドの実行について
Ruby での外部コマンドの実行についてRuby での外部コマンドの実行について
Ruby での外部コマンドの実行について
 
Ruby のワンライナーについて
Ruby のワンライナーについてRuby のワンライナーについて
Ruby のワンライナーについて
 
AWS のコスト管理をちゃんとしたくてやったこと
AWS のコスト管理をちゃんとしたくてやったことAWS のコスト管理をちゃんとしたくてやったこと
AWS のコスト管理をちゃんとしたくてやったこと
 
PostgreSQL のイケてるテクニック7選
PostgreSQL のイケてるテクニック7選PostgreSQL のイケてるテクニック7選
PostgreSQL のイケてるテクニック7選
 
HTTPと Webクローリングについて
HTTPと WebクローリングについてHTTPと Webクローリングについて
HTTPと Webクローリングについて
 
Rake
RakeRake
Rake
 
Active record query interface
Active record query interfaceActive record query interface
Active record query interface
 
Active Support のコア拡張機能について
Active Support のコア拡張機能についてActive Support のコア拡張機能について
Active Support のコア拡張機能について
 
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナー
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナーRuby ビジネス創出展 Ruby初心者向けプログラミングセミナー
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナー
 
RubyのDir、File、IO について
RubyのDir、File、IO についてRubyのDir、File、IO について
RubyのDir、File、IO について
 
Thread の利用事例紹介
Thread の利用事例紹介Thread の利用事例紹介
Thread の利用事例紹介
 
Ruby の制御構造とリテラルについて
Ruby の制御構造とリテラルについてRuby の制御構造とリテラルについて
Ruby の制御構造とリテラルについて
 

Recently uploaded

【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案sugiuralab
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 

Recently uploaded (8)

【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 

フィボナッチ数列の作り方

  • 2. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 自己紹介 最近のできごと Dell XPS 12 を買いました。 不思議なギミックでタブレットになる Full HD、Touch Panel、Display Portポート Office 365 Home Premium に契約しました 毎月 $9.99 で Office の最新版を利用可能 パワポ、エクセル、ワードを最大5台にインストール可能 (2013年2月2日現在)日本では、まだサービス開始していません。。。 今後の勉強会 プログラマのためのサバイバルマニュアル読書会 第1回 3月2日 JR尼崎駅 徒歩2分 小田公民館で開催 11
  • 3. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 22フィボナッチ数列について 次の漸化式を満たす数列をフィボナッチ数列という フィボナッチ数列の特徴 うさぎの増え方を表現する漸化式 𝐹𝑛−1 𝐹𝑛 が 黄金比( 5−1 2 = 0.683 …) に収束する プログラミングにおけるフィボナッチ数列 関数型プログラミング言語における Hello, World! 入門向けに使える程度の複雑さ 切り口によって、いろんな説明ができる 今回は、フィボナッチ数列の求め方をいろいろ説明します。 𝑭 𝒏 = 𝟎 𝟏 𝑭 𝒏−𝟏 + 𝑭 𝒏−𝟐 𝒏 = 𝟎 𝒏 = 𝟏 𝒏 ≥ 𝟐
  • 4. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 単純な実装 33 a = 0; b = 1 loop do a, b = b, a + b break if 100 < a puts a end ■ (1) もっとも単純な実装 ■ (2) 多重代入の利用 もっとも単純なフィボナッチ数列の Ruby による実装 ポイント: ループ、多重代入、while の構文 a = 0; b = 1 loop do tmp = a a = b b = tmp + b break if 100 < a puts a end a = 0; b = 1 while a < 100 puts b a, b = b, a + b end ■ (3) while の利用
  • 5. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 ブロック付メソッド 44 ■ (4) ブロック付メソッド呼び出し ■ 処理の実施順 yield キーワードにより、ブロック引数に値を渡せる。 ブロック付メソッド呼出しにより、 値の生成と、値の利用の処理を分離できる def fibonacci a = 0; b = 1 loop do a, b = b, a + b yield a end end n = 1 fibonacci do |i| break if 100 < a puts “#{n} #{i}" n += 1 end ① ② ③ ⑤ ⑦ ⑤ → ① → ② → ⑦ → ③ → ② → ⑦ → ③ → ② → ⑦ → ③ ・・・ (以下おなじ)
  • 6. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 クラスの利用 55 ■ (5) クラスの利用 クラスを利用し、内部状態をインスタンス変数に持たせる方法もある この場合は、next を実行したときに内部状態が変化する。 class Fibonacci def initialize @a = 0; @b = 1 end def next @a, @b = @b, @a + @b return @a end end fibonacci = Fibonacci.new loop do i = fibonacci.next() break if i > 100 puts i end インスタンス変数の初期化インスタンス変数の初期化 次の値の生成次の値の生成
  • 7. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 クロージャ 66 ■ (6) クロージャの利用 クロージャという機能により、ブロックの中から ネストの外側の変数を参照できる。 内部状態を持つ関数を簡易に作ることができる。 fibonacci = proc do a = 0; b = 1 lambda do a, b = b, a + b return a end end.call() loop do i = fibonacci.() break if i > 100 puts i end スコープを導入するためのクロージャスコープを導入するためのクロージャ 外側のクロージャを呼ぶ出すための Proc#call外側のクロージャを呼ぶ出すための Proc#call 内側のクロージャを作るための lambda 中で return を使いたいので 「 lambda 」にしている。 内側のクロージャを作るための lambda 中で return を使いたいので 「 lambda 」にしている。 クロージャを呼び出し、Fibonacci 数列の次の値を取得するクロージャを呼び出し、Fibonacci 数列の次の値を取得する
  • 8. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 Ruby 1.8: Generator の利用 77 ■ (7) Generator の利用 Ruby 1.8 には、標準ライブラリに Generator があった 内部実装に callcc を使うので、ちょいと遅い require 'generator' g = Generator.new do |yielder| a = 0; b = 1 loop do a, b = b, a + b yielder.yield a end end g.each do |i| break if i > 100 puts i end Generator が生成する項を順に取得するGenerator が生成する項を順に取得する 次の値を生成する次の値を生成する
  • 9. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 Ruby 1.9: Enumerator の利用 88 ■ (8) Enumerator の利用 Ruby 1.9 では Enumerator を利用可能 内部実装に Fiber を使うため、高速 Enumerable モジュールのメソッド(each_cons など)を利用可能 e = Enumerator.new do |yielder| a = 0; b = 1 loop do a, b = b, a + b yielder << a end end e.each do |i| break if i > 100 puts i end Enumerator が生成する項を順に取得するEnumerator が生成する項を順に取得する 次の生成する値を yield する次の生成する値を yield する Enumerator による実装は、 利用側のコード行数がコンパクト になる。
  • 10. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 (参考) Enumerator と Fiber 99 e = Enumerator.new do |yielder| a = 0; b = 1 loop do a, b = b, a + b yielder << a end end e.each do |i| break if 100 < i puts i end ■ (8) 《再掲》 Enumerator の例 fib = Fiber.new do a = 0; b = 1 loop do a, b = b, a + b Fiber.yield a end end def fib.each loop do yield self.resume end end fib.each do |i| break if 100 > i puts i end ■ 《参考》 (9) Fiberの例 Enumerator は Fiber を活用するデザインパターンの1つ Fiber における難しい概念を隠ぺい Fiber.yield => Enumerator::Yielder#<< 、 Enumerator#each による列挙 Enumerator を使いこなせれば、十分 Fiber のメリットを活用できる 《参考: Fiber にできて、Enumerator でできないこと》 親 Fiber から 子Fiber へのデータの送付(Fiber.yield の返り値の利用) これが必要。 だけど、これが 難しい。(汗) Enumerator の 内部実装まで 考えなくていい
  • 11. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 Enumerator はベンリ 1010 fib = Enumerator.new do |yielder| a = 0; b = 1 loop do a, b = b, a + b yielder << a end end fib.each do |i| break if 100 < I puts i end fib.each_cons(2) do |i, j| break if 100 < i puts "#{i} #{j}" end ■ (10) Enumerator の例 def fibonacci a = 0; b = 1 loop do a, b = b, a + b yield a end end fibonacci do |i| break if 100 < i puts i end prev = nil fibonacci do |i| break if 100 < i puts "#{prev} #{i}" if prev prev = i end ■ 《参考》 (11) ブロック付メソッド呼び出しの例 Enumerator なら Enumerable の便利メソッドを使える。 ブロック付メソッド呼び出しは単純なイテレーションならいいけど。。。 Enumerator はオブジェクトなので、使い回しが簡単。 引数にしたり、返り値にしたり、インスタンス変数に格納したり Enumerator オブジェクトの生成も慣れれば簡単。 慣れれば、 カンタン 面倒 ! ! Enumerable の便利メソッド を使い放題 単純なイテレーション ならいいけど・・・。
  • 12. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 Enumerable#lazy の利用 1111 fib = Enumerator.new do |yielder| a = 0; b = 1 loop do a, b = b, a + b yielder << a end end fib.select do |i| i < 100 end. take(10).each do |i| puts i end ■ (12) うまく動かない例 fib = Enumerator.new do |yielder| a = 0; b = 1 loop do a, b = b, a + b yielder << a end end fib.lazy.select do |i| i < 100 end.take(10).each do |i| puts i end ■ (13) Enumerable#lazy を利用する例 Ruby 2.0.0 から、Enumerable#lazy が利用可能となる Enumerable#lazy を使うと、遅延評価になり、無限を無限のまま扱える 宇宙ヤバい Ruby 1.9 でも gem でインストール可能 @yhara さんの作品 ここで、無限ループに なり、うまく動かない。 ※ take_while を 使う方法もある。 Enumerable#lazy を使えば、正しく 期待通りに動作する
  • 13. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 (参考)Enumerable#lazy の実装(Ruby 2.0 での実際の実装とは異なる) 1212 module Enumerable def lazy Enumerator::Lazy.new(self) end end class Enumerator class Lazy < Enumerator def initialize(obj, &block) super(){|yielder| begin obj.each{|x| if block block.call(yielder, x) else yielder << x end } rescue StopIteration end } end def select(&block) Lazy.new(self){|yielder, val| if block.call(val) yielder << val end } end def take(n) taken = 0 Lazy.new(self){|yielder, val| if taken < n yielder << val taken += 1 else raise StopIteration end } end …… end Enumerable#lazy を使うと、Enumerable のメソッドの返り値が Enumerator::Lazy オブジェクトになる Enumerable モジュールに増やすメソッドは Enumerable#lazy だけ
  • 14. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 単純な再帰と末尾再帰 フィボナッチ数列を再帰で求めてみる 関数型プログラミング言語の入門には、ほぼ必ず登場する例 適度な難易度で説明しやすい 末尾再帰による高速化、遅延評価とかを説明できる 1313 # めちゃくちゃ速い : O(n) の速さ def fib n, a = 0, b = 1 return a if n == 0 return fib(n-1, b, a+b) end # def fib_nonrecursive n # a = 0; b = 1 # loop do # return a if n == 0 # n, a, b = n-1, b, a+b # end # end (0..30).each do |n| puts fib(n) end # めちゃくちゃ遅い (指数関数オーダ) def fib n return n if n <= 1 return fib(n-1) + fib(n-2) end (0..30).each do |n| puts fib(n) end ■ (14) 単純な再帰、n項を取得 ■ (15) 再帰の例(高速版) 末尾再帰のコードと まったく同じ処理を 再帰を使わずに 書くとこうなる。
  • 15. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 再帰と memoize memoize という高速化手法がある 最初の一度だけ計算し、2回目以降は前回計算済みの値を返す メモリを多く消費するが、計算時間を短縮できる 同じ計算を繰り返すときは、コストに見合う高速化効果が得られる 遅い再帰でも memoize することで、大幅に高速化できる 1414 # memoize版。同じ計算は1度だけ。圧倒的に速い。 def add a, b memo = nil lambda do return memo if memo memo = a.() + b.() return memo end end fib = Enumerator.new do |yielder| a = lambda{ 0 } b = lambda{ 1 } loop do a, b = b, add(a, b) yielder << a end end fib.take(36).each do |i| puts i.() end # memoize しない場合。同じ計算を何度もする。 # すごい遅い。 def add a, b lambda do return a.() + b.() end end fib = Enumerator.new do |yielder| a = lambda{ 0 } b = lambda{ 1 } loop do a, b = b, add(a, b) yielder << a end end fib.take(36).each do |i| puts i.() end ■ (16) memoize しない例 ■ (17) memoize する例
  • 16. 2013/2/2 第56回Ruby勉強会 「フィボナッチ数列のつくり方」 1515まとめ 単純な問題だけど、いろんな解法がある ループ、ブロック付メソッド、クラス、クロージャ、 Enumerator、再帰 個人的オススメは、Enumerator による実装 利用側のコードがコンパクト Enumerable モジュールの便利メソッドが使える Enumerable#lazy とか 再帰はとくに実装がコンパクトになる ただし、注意しないと非常に遅い実装になることもある 遅いときも下記の指針に従うことで、高速化できる。 更新が必要な内部状態を引数に持ってくるように引数を見直す memoize を使って、計算を一度だけにする。