らんたくいっくそーと
数学ガール4巻を読んでいたら乱択クイックソートが出てきたのでPythonで書いてみた。本には疑似コードまで載せてあって読みやすい。
・普通のクイックソート
・乱択クイックソート
main()内でソートするリストの要素をrandint()で100万生成してそれをクイックソートする。一応最後にPythonに元からあるリストのソートと同じ結果になっているかの確認をする。比較のためにseed値を固定しておく。
実行結果がこちら。
・ふつうの
start time: 9.663000 True
・乱択
start time: 11.829000 True
乱択クイックソートの方が少し遅い。何回か繰り返してみたけど大体同じ感じだった。
次にソート済みのリストに対してソートをかけてみる。
c = range(9000)
c = range(9000, 0, -1)
として実行してみた結果がこちら。
ソース | クイックソート | 乱択クイックソート |
---|---|---|
c = range(9000) | 6.739000 | 0.071000 |
c = range(9000, 0, -1) | 13.412000 | 0.074000 |
最初にやったやつ | 9.663000 | 11.829000 |
だいたいこんな感じになった。
ソート済みのリストに対しては乱択クイックソートの方が圧倒的に速いことがわかる。
ソートする対象が、すでにソートされている部分があるかどうかわからないときは乱択クイックソートを使うのも良いかもと思った。
Fortranでの配列の要素へのアクセス順序について
Fortranの配列では列優先でメモリに格納されるそうだ。
Fortranの多次元配列は列優先 (Column Major) です。(C/C++言語では行優先)例えば3行4列の2次元整数配列は integer a(3,4) のように宣言され、メモリ上には以下の順番で数値が格納されます。
a(1,1) a(2,1) a(3,1) a(1,2) a(2,2) a(3,2) a(1,3) a(2,3) a(3,3) a(1,4) a(2,4) a(3,4)Fortran 入門: 配列
ということで以下のプログラムを使って実際に比べてみた。使用したマシンはちょっと昔のiMac。
program ArrayTest implicit none integer :: a(1000, 1000) = 0 integer :: n = 1000 real :: s = 0 integer i, j, k do k = 1, 5000 do j = 1, n do i = 1, n a(i, j) = j - i s = a(i, j) end do end do end do print *, s end program ArrayTest
program ArrayTest2 implicit none integer :: a(1000, 1000) = 0 integer :: n = 1000 real :: s = 0 integer i, j, k do k = 1, 5000 do i = 1, n do j = 1, n a(i, j) = j - i s = a(i, j) end do end do end do print *, s end program ArrayTest2
2つとも1000×1000の2次元配列の端から端までアクセスするのを5000回繰り返すだけのプログラム。上のほうは列優先でアクセスし、下のほうは行優先でアクセスする。最後のprintは特に意味はない。ループが終わったことの目印になればいいかと思ったけど別にいらないような…
timeコマンドで時間を測った結果がこちら。
・列優先のほう
0. real 0m30.697s user 0m30.297s sys 0m0.070s
・行優先のほう
0. real 0m42.868s user 0m42.522s sys 0m0.145s
なるほど確かに列優先だ。
じゃあ3次元配列も同じような感じなのかしら?ってことで調べてみた。
program ArrayTest3D implicit none integer :: a(100, 100, 100) = 0 integer :: n = 100 real :: s = 0 integer i, j, k, iter do iter = 1, 2000 do k = 1, n do j = 1, n do i = 1, n a(i, j, k) = k - j - i s = a(i, j, k) end do end do end do end do print *, s end program ArrayTest3D
program ArrayTest3D2 implicit none integer :: a(100, 100, 100) = 0 integer :: n = 100 real :: s = 0 integer i, j, k, iter do iter = 1, 2000 do i = 1, n do j = 1, n do k = 1, n a(i, j, k) = k - j - i s = a(i, j, k) end do end do end do end do print *, s end program ArrayTest3D2
上のほうが列優先で、下のほうが行優先。i,j,kの組み合わせはほかにもあるけどとりあえずこの2つでやってみた。
結果はこちら。
・列優先のほう
-100. real 0m30.861s user 0m30.845s sys 0m0.012s
・行優先のほう
-100. real 0m34.517s user 0m34.498s sys 0m0.012s
2次元配列の時ほどではないけど、上のほうが速いことがわかる。
上のほうでのアクセス順序がi,j,kの組み合わせの中で一番速いのかな?
ということで、Fortranで配列をループで扱うときはアクセスする順番に気を付けましょうというお話でした…
お手製timeコマンドをつくってみたい
Windowsでもtimeコマンド使いたいなーなんてときがしばしばあるので試しに作ってみようってことで書いてみた。
Windowsだと別の役割を持つtimeコマンドがすでにあるのでtimeitという名前に。
WindowsAPIのCreateProcess関数とGetProcessTimes関数を用いた。
FILETIME構造体は、1601年1月1日から 100 ナノ秒間隔の数を表す二つの 32 ビットメンバを持つ 64 ビットの値で、
typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME;
となっているので、ポインタのキャストで無理やりlong long int にして扱った。
ただ、これはexeファイルしかuserとkernelの時間が測れないという問題がある。内部コマンドやバッチファイルは受け付けてくれない。また、
cmd /c
を先頭に入れると内部コマンドやバッチファイルを走らせることができるが、これだと新しく開いたプロンプトの時間を監視することになるので正しい時間が測れない。
どうしたらいいんでしょう……
参考にしたところ
- ファイル時間情報
- Win32API プロセスに関する時間情報を取得する GetProcessTimes - s-kita’s blog
- Windows previous versions documentation | Microsoft Docs
- Windows previous versions documentation | Microsoft Docs
- CreateProcessによるプログラム起動と制御
等々
VimでF5を押してコンパイル&実行する
数字→ローマ数字変換
なんとなく数字をローマ数字に変換するスクリプトを書いてみた。1から9999までの数字を変換することができる。数字を受け取ったら1の位から順にチェックしていくってだけのもの。
実行例がこちら。
>>> 153 CLIII >>> 48531 Error: input 1 ~ 9999 3587 MMMDLXXXVII
んー・・・もっと良い方法があるはず。
vim-indent-guidesを入れてみた
ある日vimテクニックバイブルをちらりと読んでみたらvim-indent-guidesというものを見つけた。Python使うしインデントが見えると助かるよなってことで導入することにした。ファイルは次のサイトでダウンロードできる。
・GitHub - nathanaelkane/vim-indent-guides: A Vim plugin for visually displaying indent levels in code
zipを展開して出てきたautoload,doc,pluginをそれぞれvimのruntimeディレクトリにぶち込めばOKみたい。
で、vimrcに次の2行を追加した。
let g:indent_guides_enable_on_vim_startup=1 let g:indent_guides_guide_size=4
さてうまくいくかなとgvimを起動してみたら上手くインデントが色づけされててよかったのだが、コンソール版のvimを起動してみたら次のエラーが出た。
function <SNR>14_IndentGuidesEnable..indent_guides#enable..indent_guides#init_sc ript_vars..indent_guides#capture_highlight の処理中にエラーが検出されました: 行 2: E411: ハイライトグループがみつかりません: Normal
・・・ハイライトグループが見つからないってことは何か色の設定が見つからないってことなのかな・・・?なんて思いながら配布サイトの説明を読んでたら、colorscheme設定しとけ的なこと書いてあったので設定してみたら(というか今まで設定していなかったのかよ・・・)エラーが出なくなった。めでたしめでたし。
細かい設定についてはdocの中にあるテキストファイルに書いてあるっぽいから暇な時に眺めてみよう。
Processingを触ってみた
最近、Processingというものを知った。詳しくは以下のサイトで。ググるといろんなサイトが出てくる。
・Processing.org
・ポケットサーバー 格安レンタルサーバー
OpenProcessingというサイトに行くといろんな作品を見ることができて楽しい。ソースコードも一緒に公開されているので勉強にもなるかもしれない。
・OpenProcessing - Creative Coding for the Curious Mind
今回はためしにグモウスキー・ミラの写像をパラメータをどんどん変えていってアニメーションさせてみた。グモウスキー・ミラの写像って何?って人はググってください。
コードはこちら。とりあえずハイライトはjavaにしておいた。
float a = 0.0; float b = 0.06; boolean f = true; void setup(){ size(400, 400); frameRate(10); background(255); } void draw(){ translate(width/2,height/2); background(255); float x = 0.0; float y = 0.0; float newx = 0.0; float newy = 0.0; int i = 0; for(i = 0;i < 30000; i++){ newx = y + a*(1 - 0.05*y*y) + b*x + 2*(1-b)*x*x/(1+x*x); newy = -x + b*newx + 2*(1-b)*newx*newx/(1+newx*newx); x = newx; y = newy; point(x*20,-y*20); } a += 0.005; } void mouseClicked(){ if (f == true){ noLoop(); f = false; } else{ loop(); f = true; } }
再生してみるとこんな感じになった。
元の動画は1分ほどの長さなのになぜか再生時間が2分ほどになってる…
動画の後半は何なんだろう…
もちろん、元々1分しかないんだから後半は動くわけがない…