bm_so_partial_sums.rbが動き始めた
追記 2009/8/25
nagachikaさん、ブックマークのコメントありがとうございます。正直この日記にコメントが付くとは思っていなかったのでうれしかったし、ビックリしました.
同じ名前の変数を、違う型として扱われるプログラム中の区間を区切って別物として扱う件は、そんなに深く考えずに書いたものでした。今日、ちょっと考えてみたのですが、条件分岐が含まれると完全には出来ないです。例えば、
if cond then d = 1.0 else d = 1 end foo(d) # fooの型は?
ただし、この様な場合はcondの値が静的に決まる特別な場合を除いて本質的に静的に型を決定できない場合じゃないかなと思います。この様な場合は素直に動的に型チェックを生成すべきだと思います。
基本ブロック内であれば、区間で区切って別物として扱うことは、多分常に可能じゃないかなと思っています。そして、例えば一時変数をtempとしていろいろ使いまわすとかありがちかなと思いますが、そういうのは基本ブロック内のみサポートで結構コンパイル可能になるんじゃないかなと思います。
追記終わり
bm_so_partial_sums.rbが少しの変更で動く様になりました。まだ、オリジナルが動くわけではないのですが、結構面白い動きをするので、ここに書いておきます。
bm_so_partial_sums.rbは一見すると、コンパイルが簡単なように見えます。
n = 2_500_000 # (ARGV.shift || 1).to_i alt = 1.0 ; s0 = s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = 0.0 1.upto(n) do |d| d = d.to_f ; d2 = d * d ; d3 = d2 * d ; ds = Math.sin(d) ; dc = Math.cos(d) s0 += (2.0 / 3.0) ** (d - 1.0) s1 += 1.0 / Math.sqrt(d) s2 += 1.0 / (d * (d + 1.0)) s3 += 1.0 / (d3 * ds * ds) s4 += 1.0 / (d3 * dc * dc) s5 += 1.0 / d s6 += 1.0 / d2 s7 += alt / d s8 += alt / (2.0 * d - 1.0) alt = -alt end # if false # 現状はここをコメントアウトしないと動かない printf("%.9f\t(2/3)^k\n", s0) printf("%.9f\tk^-0.5\n", s1) printf("%.9f\t1/k(k+1)\n", s2) printf("%.9f\tFlint Hills\n", s3) printf("%.9f\tCookson Hills\n", s4) printf("%.9f\tHarmonic\n", s5) printf("%.9f\tRiemann Zeta\n", s6) printf("%.9f\tAlternating Harmonic\n", s7) printf("%.9f\tGregory\n", s8) # end # 現状はここをコメントアウトしないと動かない
ところが、これがなかなか曲者なんです。曲者なのが、
1.upto(n) do |d| d = d.to_f ;
のくだりです。普通考えるとdの型が決まりません。Rubyの型なら何でも入るVALUE型にしておいて動的に型チェックするという方法も考えられますが、それでは型推論の意味がなくなってしまいます。
現在のバージョンのyarv2llvmではdの型をFloat型と推論します。そうするとuptoメソッドから渡ってくる整数値の扱いに困るわけですが、整数が来たときは型変換命令を出力することで対処しています。厳密にはブロックの開始からd = d.to_fまでの間はdには整数が入っているので正しくないのですが、そこまで凝る必要はないのではないかなと今は思っています。必要であるなら、整数版dとFloat版dを別々に用意することも出来るかなと思います。
ちなみに実行時間はこんな感じです。こういうプログラムは速いです。
$ time ruby yarv2llvm.rb ~/src/ruby/benchmark/bm_so_partial_sums.rb 3.000000000 (2/3)^k 3160.817621887 k^-0.5 0.999999600 1/k(k+1) 30.314541510 Flint Hills 42.995233998 Cookson Hills 15.309017155 Harmonic 1.644933667 Riemann Zeta 0.693146981 Alternating Harmonic 0.785398063 Gregory real 0m2.176s user 0m2.128s sys 0m0.048s $ time ruby ~/src/ruby/benchmark/bm_so_partial_sums.rb 3.000000000 (2/3)^k 3160.817621887 k^-0.5 0.999999600 1/k(k+1) 30.314541510 Flint Hills 42.995233998 Cookson Hills 15.309017155 Harmonic 1.644933667 Riemann Zeta 0.693146981 Alternating Harmonic 0.785398063 Gregory real 0m16.084s user 0m16.077s sys 0m0.004s