第5話 常識に囚われるな(コンパイラの世界2)

--------------------- 第5話 常識に囚われるな(コンパイラの世界2) --------------------------


はじまり、はじまり~。


<で、どうしようもなく遅いのでコンパイラを使った結果は?>
いきなり結論ですか?

<私の性格知っているでしょ?>
はい。約217倍速でございます。

<嘘つきでございます。>
マジございます。

<アンタ今さっき速くても数十倍って言ってたじゃん!>
一般的な話でね。ところが、以前今回のような例では、超有名Cコンパイラでも8倍から10倍程度だった。

<ってどうゆう事?>
実は今回使ったコンパイラでも旧バージョンでは4倍程度の性能だった。しかし、最近仕様が変更され、連想配列も
実装されて、大幅に性能が上がった。

まあ、全てのコンパイラを試せるハズも無く、コレ以上に速いコンパイラが存在する可能性もあります。
私としては、テキストファイルをよく使うので、現状では手放せない存在となってます。

<またまた口からデマカセを・・・どうせソレに有利になるように細工したんでしょ?>
そう来ると思って、今回UWSC側は、スピードテストされ公開されているものをベースにした。(下記参照)

<ゲッ! コレって連想配列を使用した高速な重複削除プログラムじゃないの?>
今回は公正を期す為に、しきさん版を採用、100万行に固定して、テキストデータ作成時から計測した。

その結果108.5秒だった。

<まあソレなら信頼できるわね。ファイルが作られるので誤魔化せないし。でも217倍って事は0.5秒?>
<まさかねぇ。信じられないわ。そんな、とんでもない速さ。100万行よ!>

まあ論より証拠だね。ポチットな。(瞬時に終了)
<なっナンなのコレ? この速さ!!・・誤魔化しの効かないこの状況なのよ。>

<本当に100万行のファイルかしら?ダブルクリックっと・・・>
<ふゅへぇ~~~メモ帳で開く方が時間がかかってるぅ。>

<チョイ待ち!! 359msって表示してあるんですけど?>
ああソレ?連想配列だから、多少の誤差はあるよ。何度か実行してみると分かるよ。

<誤差って速い方のですか・・・ええい! こうなったらホチホチしてやるんだからぁ。>
<360ms, 422ms, 496ms, なっ297ms!!, 513ms, 407ms, 594ms, 432ms・・・コレってマジで100万行なんだよね?>

<はあっ~。100万行の重複削除が、600ミリ秒以下の平均280倍速以上で時には360倍速って・・・こっこんな事が・・・>
<速いにもほどかある!!!>

やっぱ嘘つきでした。217倍速じゃ無くって280倍速でした。アハハ!

<分かったから。で、結論として言いたい事はナンなの?>
常識に囚われ無いこと。今回のように速さだけでなく、プログラミング全域においてまだまだ可能性はありますよ。

<コレを見ていると、まんざら嘘でもないみたい。それにしても、どんなけ最適化しているのかねぇ?この速さは>
<メガクラスのランタイムにメモリを食いつぶしてたりしてね。>

ランタイムはないよ完全独立タイプ(スタンドアローン)だからね。
<そうなの?珍しいわね。 だったら、サイズは?スタンドアローンなら500Kくらいはあるわよね普通。>
10K。

<ソースプログラムが?>
実行プログラムがです。

<小さいにも、ほどがある!!>
<ナンなのコノ高速コンパクトな世界は・・・>
コンパイラの世界です。 普段、巨大で鈍足なプログラムに慣れきっている我々には新鮮に映るかもね。

<コレがパソコン本来の速さなのね>
ようやく気付いてくれましたか。

<それにしてもアンタUWSC以外でもプログラム組めたのね。>
今頃何を? ステゴザウルス並みの神経だね。

<何ソレ?>
シマッタ!。まず最初にコイツから高速化しておくべきだった。。

 

----------------------------------------------------------------------

提供は: 天使って神経あるのかな? と思うLinersでした。

----------------------------------------------------------------------

// 連想配列による重複行の削除 のスピード比較
// 今回は記述の違う2大先生のスクリプトを比較するという、ちょっとやらしい企画をします。
// 提供 Liners さん http://www.nagomi-jp.net/~liners/p0b.htm
// 提供 しき さん http://www3.bigcosmic.com/board/s/board.cgi?id=umiumi&cnt=1&no=457

// 2007/01/04 新規作成

MaxLine = 10
for i = 1 to 4
MaxLine = MaxLine * 10
Run_Comparison(MaxLine)
next

// 結果はこんな感じでした。
// 07/01/04 21:43 100件で比較 Linersさん 0.02秒
// 07/01/04 21:43 100件で比較 しきさん 0.03秒
// 07/01/04 21:43 1000件で比較 Linersさん 0.12秒
// 07/01/04 21:43 1000件で比較 しきさん 0.18秒
// 07/01/04 21:43 10000件で比較 Linersさん 0.802秒
// 07/01/04 21:43 10000件で比較 しきさん 1.231秒
// 07/01/04 21:44 100000件で比較 Linersさん 8.332秒
// 07/01/04 21:44 100000件で比較 しきさん 12.448秒
// 07/01/04 21:47 1000000件で比較 Linersさん 1分21.548秒
// 07/01/04 21:49 1000000件で比較 しきさん 2分11.799秒

// よって、hash_exists を使用するより、ループを2回使用したほうが速いという結論がでました。
// いかがでしたでしょうか?


////////////////////////////////////////////////////////////////////////////////////////////////////
// 専用 関数郡 // 2007/01/04 新規作成

// 比較実行
procedure Run_Comparison(MaxLine)
// しきさん版
fukidasi(MaxLine + "件で比較 テキストデータ作成中")
FileName = "Test.txt"
CreateText(FileName,MaxLine)

// Linersさん版 計測
fukidasi(MaxLine + "件で比較 Linersさん版実行中")
TimeCheckStart();重複行削除_Linersさん版(FileName);TimeCheckEnd()
print MaxLine + "件で比較 Linersさん " + TimeCheckShow2()

// しきさん版 計測
fukidasi(MaxLine + "件で比較 しきさん版実行中")
TimeCheckStart();重複行削除_しきさん版(FileName);TimeCheckEnd()
print MaxLine + "件で比較 しきさん " + TimeCheckShow2()
fend

 

// テキストデータ作成
procedure CreateText(FileName,MaxLine)
ID_f = fopen(FileName,f_write)
for i = 0 to MaxLine
fput(ID_f,random(100),i)
next
fclose(ID_f)
sleep(0.1)
fend
exit


// 連想配列で重複行削除1
// Linersさん版 読込先行でループは2回
procedure 重複行削除_Linersさん版(FileName)
HASHTBL hash = HASH_CASECARE

fp=fopen(FileName,F_READ)
for i=1 to fget(fp,-1)
hash[fget(fp,i)]=1 // 1 はダミー
next
fclose(fp)

fp=fopen("1_" + FileName,F_write)
for i=0 to length(hash)-1
fput(fp,hash[i, HASH_KEY])
next
fclose(fp)
fend

 

// 連想配列で重複行削除2
// しきさん版 読書同時でループは1回
procedure 重複行削除_しきさん版(FileName)
fid = fopen(FileName, f_read)
fid_new = fopen("2_" + FileName, f_write)
hashtbl hs = hash_casecare
for i=1 to fget(fid, f_linecount)
s_line = fget(fid, i) //一行データ
if hs[s_line, hash_exists] then continue //既存なら排除
hs[s_line] = i

fput(fid_new, s_line)
next
fclose(fid)
fclose(fid_new)
fend


////////////////////////////////////////////////////////////////////////////////////////////////////
// タイムチェック 関数郡 // 2006/11/27 修正

// タイムチェックスタート // 2006/10/22 作成
procedure TimeCheckStart()
public TCS
public TCS_ZZ
gettime()
TCS = gettime()
TCS_ZZ = G_TIME_ZZ / 1000
fend

// タイムチェックエンド // 2006/10/22 作成
procedure TimeCheckEnd()
public TCE
public TCE_ZZ
gettime()
TCE = gettime()
TCE_ZZ = G_TIME_ZZ / 1000
fend

// 時間表示 秒 // 2006/10/22 作成
function TimeCheckShow()
result = (TCE - TCS) + (TCE_ZZ - TCS_ZZ)
fend

// 時間表示 時分秒 // 2006/11/27 作成 提供は らしゃん さんです。
function TimeCheckShow2()
全秒 = ( TCE - TCS )
時 = int(全秒 / 3600)
分 = int((全秒 - (時*3600)) / 60)
秒 = 全秒 - ((時*3600) + (分*60)) + (TCE_ZZ - TCS_ZZ)

dim 処理時間
if 時 <> 0 then 処理時間 = 時 + "時間"
if 分 <> 0 then 処理時間 = 処理時間 + 分 + "分"
if 秒 <> 0 then 処理時間 = 処理時間 + 秒 + "秒"

result = 処理時間
fend