2010-11-06

素数を列挙する #2

前回の続き。

素数表の検索にバイナリサーチを使う

前回、素数の判定法としてはもっとも素直な「√n 以下の整数で割る」よりは割り算が少なくなると考え、素数表を使った「√n 以下の素数で割る」方法を実装してみた。ところが、列挙範囲の素数表が完成している場合であっても(つまり割り算は一度も行わない)、「√n 以下の整数で割る」方が速いという結果になった。

その原因は Array#include? を使った素数表の検索にあるのではないかと考え、今回は検索に「バイナリサーチ(二分検索)」を使ってみることにした。

(listprimes_binsearch.rb より)
def ($primes).binsearch(n)
  len = self.size
  first = 0
  last = len - 1
  while len > 0
    mid = first + len / 2
    v = self[mid]
    if n == v
      return true
    elsif n < v
      last = mid - 1
    else
      first = mid + 1
    end
    len = last - first + 1
  end
  false
end

結果として、Array#include? を使ったものより高速になったことはもちろん、(素数表が完成していれば)列挙する範囲によっては「√n 以下の整数で割る」ものよりも速くなった。とはいえ、やはり素数表を生成しながらの場合は、比較にならないほど遅い。

エラトステネスの篩

素数表の生成でもう少し速そうな方法を試してみることにした。有名な「エラトステネスの篩」だ。コードを以下に示す。

「√n 以下の素数で割る」版、「篩」版、そして「シンプルに √n 以下の整数で割る」版を実行してみた結果は以下のようになった。

[imac] mnbi% rm primes.txt
[imac] mnbi% time ./listprimes_binsearch.rb 100000 100
START (99991):
100003 (66)
100019 (66)
100043 (66)
100049 (66)
100057 (66)
100069 (66)
Elapsed: 0.000275
./listprimes_binsearch.rb 100000 100  17.60s user 0.02s system 100% cpu 17.601 total
[imac] mnbi% time ./listprimes_sieve.rb 100000 100
100003
100019
100043
100049
100057
100069
Elapsed: 0.019148
./listprimes_sieve.rb 100000 100  0.02s user 0.00s system 83% cpu 0.033 total
[imac] mnbi% time ./listprimes_simple.rb 100000 100
100003 (158)
100019 (158)
100043 (158)
100049 (158)
100057 (158)
100069 (158)
Elapsed: 0.00028
./listprimes_simple.rb 100000 100  0.01s user 0.01s system 89% cpu 0.020 total

「篩」版は確かに速いが、「シンプル」版はさらに速い。

もっとも、これは表示させる領域を大きな数を基点として「狭めて」いるから起きることだ。1 から 100000 までの範囲の素数を列挙するなら「シンプル版」の方が遅くなる。

一番、速いのは

範囲(それも比較的大きな数から始まるものを)を指定して列挙させる場合、速いのは「√n 以下の整数で割る」方法をシンプルに実装したものだ。2 から始まる素数表を生成する方式では、範囲の上限に至るまでのすべての素数を生成する分不利になる。

たとえば、画面に一定範囲にふくまれる素数を表示する(だけの)アプリを作るとしたら、素数表を作る方式は適さないことになる。画面に表示できる範囲は限られているのだから、素数表を(作って)保持しておくより、見えている分だけをシンプルな方法(√n 以下の整数で割る)で判定する方がずっと素早く表示できるはずだ。

関連リンク

関連記事

2010-11-05

素数を列挙する

プログラミングの練習。指定された範囲にある素数を列挙するプログラムを作ってみる。

素数表を使った判定

利用するアルゴリズムは自明のもの。つまり、正整数 n に対して √ n を超えない素数で割り切れるかどうかをチェックしている。初回の実行では 2 (最小の素数)から始めて素数表を作っている。実行中に作った素数表は最後にファイルに書き出す。2 回目以降の実行では、以前に作った素数表を読み込んでいる。

列挙した素数の後にカッコ付きで表示する数字は計算回数だ。

検証

念には念を入れて、listprimes.rb で作られた primes.txt を検証する。以下がそのプログラムだ。素数を判定するアルゴリズムは大して変わっていない(素数表を使わず √ n 以下の整数で割り切れるか否かをチェック)から、どちらかと言えばプログラムのバグを確認するためのものというべきだ。

実行結果

[imac] mnbi% ls primes.txt
ls: primes.txt: No such file or directory
[imac] mnbi% ./listprimes.rb 1000 50
START (2):
1009 (12)
1013 (12)
1019 (12)
1021 (12)
1031 (12)
1033 (12)
1039 (12)
1049 (12)
Elapsed: 0.00011
[imac] mnbi% tail primes.txt
991
997
1009
1013
1019
1021
1031
1033
1039
1049
[imac] mnbi% ./listprimes.rb 1000 50
START (1049):
1009 (0)
1013 (0)
1019 (0)
1021 (0)
1031 (0)
1033 (0)
1039 (0)
1049 (0)
Elapsed: 0.000444

初回の listprimes.rb の実行で、primes.txt が作られ、2 回目の実行では、(素数判定のための)計算がされていないことが(計算回数の表示から)読み取れる。意外なことに計算のない 2 回目の方が時間がかかっている。

「√ n 以下の整数」を使うより「√ n 以下の素数」の方が計算回数がぐっと少なくなると考えて素数表を使うようにしたんだが、実際のところでは素数表(配列)の操作にかかる時間の方が律速段階になっているようだ。素数表を使う方法で 2 回目以降の実行(つまり割り算は一切ない)でも、Time で計測してもわかるほどの差が出る。

素数表の検索を工夫すれば逆転するだろうか?

関連リンク

twitter より (2010-11-04)

  • 10:34  うん。まさにその通りだよ。「現場から入ってしまった人は、まず目的に必要なものをでっち上げ、後でそれの裏にある背景や理論を勉強すると、「なるほど〜 だからアレはあーなってたのかー!」と楽しく学習することができます。」→ http://docs.komagata.org/4654
Powered by twtr2src.

2010-11-04

MacRuby 0.7 を iMac にインストール

Mac mini に MacRuby 0.5 beta 2 をインストールしたのが、ほぼ 1 年前のこと。以来、バージョンは 0.5、0.6 と進み、先月(2010-10-01)、0.7 がリリースされた。

以前、参照した 公式 Roadmap はどうやらメンテナンスされておらず記述が古いままになっている。公式ブログから 0.5 beta 2 以降の変更を追跡してみる。

MacRuby のこれまで (0.5 〜 0.7)

0.1 〜 0.5 beta 2 までは以前にまとめた(→ 「MacRuby のこれまで (0.1 〜 0.5 beta 2)」)。ここでは、それ以降の変化を追う。

0.5 (released @ 2010-01-31)

ブログに書かれているのは以下の 3 つ。

  • HotCocoa が MacRuby プロジェクトから独立して GitHub で管理されるようになり、gem 化されたこと(使うには require 'hotcocoa' より前に require 'rubygems' が必要になる)
  • AOT (Ahead-of-Time) コンパイラで(macrubyc)、複数の rb ファイルをまとめてダイナミックライブラリにすることができるようになったこと。また、macrubyc 用のマニュアルページもできた。
  • GCD サポートが完成したこと。GCD を MacRuby で使うためのドキュメントもできた(→ An Introduction to GCD with MacRuby)。
0.6 (released @ 2010-04-30)

0.5 のリリースから 3 ヶ月で 0.6 がリリースされた。ブログには、数多くの新機能が追加されたとともに、全体的な安定性も大きく向上したと書かれている。

主要な変化として挙げられているのは以下の通り。

  • Cocoa アプリを開発できるだけの安定性を備えたこと。Xcode 上で MacRuby の AOT コンパイラを使ったアプリを開発できるようになった。
  • 実験的に、コマンドライン版のデバッガ macrubyd が提供されたこと。デバッグモードでコンパイルすれば、gdb と同様のデバッグを行うことができる。
  • GCD に対して、より抽象度の高い API (dispatch ライブラリ)が提供されたこと。チュートリアルも用意されている(→ Grand Central Dispatch for MacRuby)。
  • 基礎的なクラスを書き直したこと。
    • Hash が NSMutableDictionary を継承する新しいクラスとなった(これまでは NSMutableDictionary の別名だった)。
    • String が NSMutableString を継承する新しいクラスとなった。エンコーディングの変換に ICU framework を使うようになった。
    • Symbol がユニコード文字を扱えるように書き直された。
    • Regexp が 鬼車に代わって ICU framework を使うように書き直された。
  • Ruby (MRI) との互換性が向上したこと。
    • MRI 用に書かれた C 言語による拡張機能に対するサポートを提供。これにより Nokogiri、SQLite3、そして PostgreSQL 拡張を MacRuby から使えることを確認ずみ。
    • RubySpecs の互換性テストのうち 85% に合格。修正版ながら Rails 3 を動かすことができるようになった。MRI 1.9 のエンコーディングのサポートも向上。
0.7 (released @ 2010-10-01)

0.6 から 5 ヶ月で 0.7 がリリース。ブログによると、目立った機能の追加はないが、その分既存の機能の強化に努めたとのこと。

主要な変化として挙げられているのは以下の通り。

  • Cocoa サポートが向上したこと。
    • C ブロック のサポートを追加。ただし、BridgeSupport をインストールする必要がある。
    • sandbox 機能のサポート(Sandbox クラスを提供)。
  • 並列性とパフォーマンスが向上したこと。
  • MRI との互換性が向上したこと。RubySpecs で 90% を達成。ただし、Rails を無修正で動かすまでには至っていない。

iMac にインストールする

MacRuby のパッケージをダウンロード

公式サイトの右上には「Current Version: 0.7.1」と出ている。ところがダウンロードページにある Lates Stable Release にあるのは 0.7 へのリンク。0.7.1 を落とすには配布ファイルの置き場所を開く必要がある。以下に、0.7.1 へのリンクとあわせて書いておく。

MacRuby をインストール

ダウンロードした zip を展開すると(Finder からダブルクリックで OK)、MacRuby 0.7.1 というフォルダが作られる。この中にある MacRuby 0.7.1.pkg がインストーラだ。これをダブルクリックするとインストールが始まる。ライセンスに同意して、管理者のパスワードを入力すればインストールは完了。

ターミナルを開いて確認。

[imac] mnbi% hash -r
[imac] mnbi% which macruby
/usr/local/bin/macruby
[imac] mnbi% macruby -v
MacRuby 0.7.1 (ruby 1.9.2) [universal-darwin10.0, x86_64]
HotCocoa をインストール
[imac] mnbi% macgem list

*** LOCAL GEMS ***


[imac] mnbi% macgem search hotcocoa --remote

*** REMOTE GEMS ***

hotcocoa (0.5.1)
[imac] mnbi% sudo macgem install hotcocoa
Password:
Successfully installed hotcocoa-0.5.1
1 gem installed
[imac] mnbi% macgem list

*** LOCAL GEMS ***

hotcocoa (0.5.1)
[imac] mnbi% ls /Library/Frameworks/MacRuby.framework/Versions/0.7.1/usr/lib/ruby/Gems/1.9.2/gems
hotcocoa-0.5.1/

着実な進歩

どうやらこの 1 年間で MacRuby は着実に進歩したようだ。まあ、ブログのアナウンス記事を斜め読みするぐらいでは、具体的に何ができて、この先どこを目指しているのかまではわからないけどね。

関連リンク

関連記事

2010-11-03

twitter より (2010-11-02)

  • 09:34  なるほど。Air ってそういう位置付けだと思えばいいのか。革新(と核心)は SSD の搭載にあったってことか。軽くて(薄くて)サクサク動く。唯一の弱点は電池の持ちの悪さだな。 → http://bit.ly/cSud1e
  • 11:25  いまさらだけど、先日の Apple Special Event のビデオを見た(新しい Air が発表になったやつ)。これを見ると、今度の Air が、Mac というよりむしろ iOS デバイスに近いと思えてくる。キーボードがついて、OSX が動く iPad に見えてくる。
  • 11:27  来年(2011)の夏、Lion がリリースされて、Launchpad や Mission Control が利用できるようになれば、ますますその感が強くなるに違いない。
  • 11:30  iPhoto 11 のデモを見ていて感じたのは「あれ、これってiPadなのか(・ω・)?」ってことだ。それぐらい、iPadアプリの影響が色濃く現れていた。画面のデザイン(意匠)はとくに。
  • 11:31  iPhoto 11 のような(外観の)アプリを、Xcode 標準のビューやコントロールだけで作れるんだろうか?
  • 13:31  Mac OS X Lion の新機能として挙げられていた(説明はなかったけど)、(アプリの)自動セーブと起動時のレジューム(これもアプリの話だよね)が実現されると実は画期的なことだと思う。
  • 13:35  前者はアプリユーザをファイルの管理と操作から解放してくれるし、後者もアプリの使い方を大きく変えるはず。もちろん、アプリ側での対応ができてからの話。ま、どちらも iOS アプリでは当たり前のことだけどね。
  • 13:38  けど、はたしてユーザに受け入れられるだろうか? iOS アプリを使い慣れているユーザなら問題ない。Launche PadとMission Control に支えられたフルスクリーンアプリ(自動セーブとレジューム付き)は、iOS アプリのユーザ体験をそのまま取り込んだものだから。
  • 13:40  iOSって何、それオイシイの? と思うユーザにとってはどうだろうか。データを保存するタイミングが自由にならないことにとまどわないだろうか。ファイルが表に出てこないことに違和感を感じないだろうか。
  • 13:43  ああ、そうか。iTunes や iPhoto なんかでファイルを意識しないアプリには慣れているかもな。アプリによるってことかな。ファイルを意識させないユーザ体験を提供できるアプリは新しい操作環境で使われ、ファイルベースの古臭いアプリは旧来のデスクトップの下で使われる、と。
Powered by twtr2src.