厨二病患者のプログラミング入門

プログラミングなど主にパソコン関係のことを備忘録的に書いていく予定のブログです。

≫ EDIT

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書く事で広告が消せます。

| スポンサー広告 | --:-- | comments(-) | trackbacks(-) | TOP↑

≫ EDIT

ブログ移転しました

はてなダイアリーにブログを移転しました。
以前からはてなに移ろうかなと考えていたのですが、今日はてなでは記事に「>|言語名|」と書くだけでソースコードがハイライトされる素敵仕様が備わっているという情報を聞いたのをきっかけに移転することにしました。


新しいブログのURLはこちらです。
http://d.hatena.ne.jp/D_Rascal/

| 雑記 | 17:09 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

WhitespaceでFizzBuzz書いた

少し前にFizzBuzzを書くのが流行っていたので、遅ればせながらWhitespaceで書いてみることにしました。

Whitespaceとは、難解プログラミング言語の一種で、タブ・スペース・改行の3つの文字だけでプログラムを書いてしまおうというとんでもない言語なです。
しかし、実際使ってみると、見た目が分かり難いだけで命令の数は多く、四則演算なんかも簡単にできるため、FizzBuzz程度ならそれほど難しくはありません。
こちらが実際のソースです。

      












































































何も見えませんね。
実は、自分もここに上手くソースを書き込めている自信はありません。なので、スペースをSに、タブをTに置き換えたものを用意しました。

SSST

SSSS
S
SSSSTTSSTST
TSST
TSST
S
SSSSTTTT
TSTT
TSTS
S
SSSSTST
TSTT
TSTT
S
SSSSTT
TSTT
TSSSS
S
ST
STSSSTSTS
T
SS
S
SST

SSTS
SSSTSSSTTS
T
SSSSSTTSTSST
T
SSSSSTTTTSTS
T
SSSSSTTTTSTS
T
SSSSSSTSSSSS
T
SS
SSTT
SSSTSSSSTS
T
SSSSSTTTSTST
T
SSSSSTTTTSTS
T
SSSSSTTTTSTS
T
SSSSSTSTS
T
SS
S
SST

SSSSS
SSSTSSSTTS
T
SSSSSTTSTSST
T
SSSSSTTTTSTS
T
SSSSSTTTTSTS
T
SSSSSTSTS
T
SS
SSSST
SSST
TSSS
S
SS

SSST


このソースを実行すると、ちゃんとFizzBuzzが表示されます。
drascal@homu(22:17:12):WSpace$ ./wspace  hoge.ws
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz Buzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
Fizz Buzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz
43
44
Fizz Buzz
46
47
Fizz
49
Buzz
Fizz
52
53
Fizz
Buzz
56
Fizz
58
59
Fizz Buzz
61
62
Fizz
64
Buzz
Fizz
67
68
Fizz
Buzz
71
Fizz
73
74
Fizz Buzz
76
77
Fizz
79
Buzz
Fizz
82
83
Fizz
Buzz
86
Fizz
88
89
Fizz Buzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz


「ふえぇ…こんな難しそうなソースなんて書けないよぉ…」という方、ご安心ください。最初からバカ正直にスペースやタブを打ってこんなプログラムを書いたわけではありません。

まずはWhitespaceのチュートリアルを見てみましょう。

Whitespace tutorial

これを読むと、どのスペース・タブ・改行のパターンの組み合わせによってどの命令が実行されるのかが分かります。
まずはこの命令1つ1つに、適当な名前を付ける作業から始まります。僕は、Whitespaceのインタプリタのソース内で使われていた名前をそのまま使いました。
そのときのソースがこちらです。
Push 1
Label "main_loop"
Dup
Push 101
Infix Minus
If Zero "end"
Dup
Push 15
Infix Modulo
If Zero "put_fizzbuzz"
Dup
Push 5
Infix Modulo
If Zero "put_buzz"
Dup
Push 3
Infix Modulo
If Zero "put_fizz"
Dup
OutputNum
Push 10
OutputChar
Jump "loop_end"
Label "put_fizzbuzz"
Push 70
OutputChar
Push 105
OutputChar
Push 122
OutputChar
Push 122
OutputChar
Push 32
OutputChar
Label "put_buzz"
Push 66
OutputChar
Push 117
OutputChar
Push 122
OutputChar
Push 122
OutputChar
Push 10
OutputChar
Jump "loop_end"
Label "put_fizz"
Push 70
OutputChar
Push 105
OutputChar
Push 122
OutputChar
Push 122
OutputChar
Push 10
OutputChar
Label "loop_end"
Push 1
Infix Plus
Jump "main_loop"
Label "end"
End

Whitespaceは、主にスタックを使って演算を行います。

20111018-wspace-001.png

実行時のイメージはだいたいこんな感じです。
今度は、今書いたソースをS・T・改行で表された偽Whitespaceのコードにします。
SSST push 1

SSSS label main_loop
S
S dup -> SSSTTSSTST push 101
TSST infix minus
TSST if zero goto end
S
S dup -> SSSTTTT push 15
TSTT infix mod
TSTS if zero goto put_fizzbuzz
S
S dup -> SSSTST push 5
TSTT infix mod
TSTT if zero goto put_buzz
S
S dup -> SSSTT push 3
TSTT infix mod
TSSSS if zero goto put_fizz
S
S dup -> T
ST output_num -> SSSTSTS push 10
T
SS output_char ->
S
SST jmp loop_end

SSTS label put_fizzbuzz
SSSTSSSTTS push 'f'
T
SS output_char -> SSSTTSTSST push 'i'
T
SS output_char -> SSSTTTTSTS push 'z'
T
SS output_char -> SSSTTTTSTS push 'z'
T
SS output_char -> SSSSTSSSSS push ' '
T
SS output_char ->
SSTT label put_buzz
SSSTSSSSTS push 'b'
T
SS output_char -> SSSTTTSTST push 'u'
T
SS output_char -> SSSTTTTSTS push 'z'
T
SS ousput_char -> SSSTTTTSTS push 'z'
T
SS output_char -> SSSTSTS push '\n'
T
SS output_char ->
S
SST jmp loop_end

SSSSS label put_fizz
SSSTSSSTTS push 'f'
T
SS output_char -> SSSTTSTSST push 'i'
T
SS output_char -> SSSTTTTSTS push 'z'
T
SS output_char -> SSSTTTTSTS push 'z'
T
SS output_char -> SSSTSTS push '\n'
T
SS output_char ->
SSSST label loop_end
SSST push 1
TSSS infix plus
S
SS jmp main_loop

SSST label end


end

このときは、大量にコメントを書いておきましょう。後でわけがわからなくなります。どうせS・T・改行以外の文字は後からsedで削除されます。気にする必要はありません。
あとは、
$ sed -e 's/[^ST]//g;s/S/ /g;s/T/\t/g'

するだけです。
これであなたも今日からWhitespacer!!


今まで、「普通のプログラミング言語は空白文字の存在が無視されてて悲しい!!」なんて思った方は、ぜひWhitespaceを使ってみてください。今までソースの可読性を高めるだめだけに使用され、文法上の意味が全く無かた空白文字が日の目を見る数少い言語です。
「Whitespaceなんて使えるか!!」という方は、Pythonを使いましょう。おそらく、他の言語よりは空白を大事にしている言語です。

| その他プログラミング関係 | 18:30 | comments:1 | trackbacks:0 | TOP↑

≫ EDIT

ところでdaemonって何?

だえもんさんをdaemon化しようと思って考えたのですが、一体daemonとは何なんでしょう。
httpd, crond, etc... 自分の身の周りにもたくさんのdaemonがいます。
何となくバックグラウンドで動作して何やらいろいろと縁の下で仕事を行うソフトであるということくらいは分かりますが、厳密なdaemonの定義とは何なんでしょうか?

デーモン (ソフトウェア) - Wikipedia

技術的に厳密に言えば、UNIXは親プロセスの番号が 1 (init) で、制御端末を持たないプロセスをデーモンと認識する。


なんとなくdaemonがどういうものなのかは分かったような気がします。
では、実際にdaemon的な動作をするプログラムはどのように書けばいいのでしょう?

実は、Pythonにはpython-daemonという便利なライブラリがあり、簡単にdaemon的な動作をするプログラムが作れてしまいます。

import daemon
dc = daemon.DaemonContext()
with dc:
    行いたい動作
    ...

なんと、このように書くだけでdaemonが作れてしまいます。

しかし、

これではつまらないです。

たしかに簡単にdaemonを書くことはできましたが、内部でどんな動作を行っているのかまるで分かりません。
というわけで、実際にどのような動作を行えばdaemonが作れるのか探してみると、次のようなソースを見つけました。

import os
import sys
 
def daemonize(pidfile, daemonfunc, *args):
    try:
        pid = os.fork()
        if (pid > 0):
            sys.exit(0)
    except OSError:
        print >>sys.stderr, 'daemonize: fork #1 failed.'
        sys.exit(1)
 
    try:
        os.setsid()
    except:
        print >>sys.stderr, 'daemonize: setsid failed.'
        sys.exit(1)
 
    try:
        pid = os.fork()
        if (pid > 0):
            sys.exit(0)
    except OSError:
        print >>sys.stderr, 'daemonize: fork #2 failed.'
        sys.exit(1)
 
    try:
        f = file(pidfile, 'w')
        f.write('%d' % os.getpid())
        f.close()
    except IOError:
        print >>sys.stderr, 'daemonize: failed to write pid to %s' % pidfile
        sys.exit(1)
 
    # Now I'm a daemon.
    try:
        os.chdir('/')
        os.umask(0)
        sys.stdin.close(); sys.stdin = None
        sys.stdout.close(); sys.stdout = None
        sys.stderr.close(); sys.stderr = None
        os.close(0)
        os.close(1)
        os.close(2)
    except:
        pass
 
    daemonfunc(*args)

これは一体何をやっているのでしょうか?
上の行から順に動作を追っていきましょう。

まずは最初のfork()の部分です。ここでは子プロセスを生成し、親はこの時点で終了します。os.fork()の戻り値は親の場合は子のpidで、子の場合は0が帰ってきますので、後のif文でpidが0より大きい場合のみ終了させています。
親が死ぬと子はinitプロセスの子になります。

次はos.setsid()を呼び出して、新しいセッションを生成します。現在実行中のプロセスはこのセッションのリーダーとなります。
os.setsid()はプロセスグループリーダーからの呼び出しでは上手く動作しません。そこで、仮に親がプロセスグループリーダーであった場合でも、fork()して子を作ってしまえばその子は親の属するグループに属するわけで、つまり子はリーダーではなくなります。最初のfork()で作った子プロセスをinitの子にし、絶対にプロセスグループリーダーにはならないようにしていたわけです。

次はもう一度fork()しています。これでセッションリーダーが居なくなるので、制御端末とこのプロセスを関連付けることができなくなるそうです。
ここで生成されたプロセスがdaemonとして色々な処理を行うので、このプロセスのpidをpidfileに書き出しています。

そしてその次はカレントディレクトリを/に移動しています。その次はumask()を呼び出してプログラム中で生成するファイルのパーミッションを設定しています。
そして最後にstdin, stdout, stderrを閉じれば、daemonの完成です。やったね!


と、まあ、こんな感じでdaemonは作られているわけです。
これでだえもんさんをdaemon化することができました。もう一日中メイン機の電源を付けっぱなしにしなくても済みます!
これからはサーバー機にsshでログインしてだえもんさんさーばーを起動、そのままログアウトしてメイン機は電源を切ってしまえばいいわけです!!

| Python | 22:56 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

k平均法を覚えた

機械学習の学習の一環として、教師なし学習の一つであるk平均法というものを勉強しました。
k平均法とは、大量のデータをクラスタ分けするときに使われるアルゴリズムです。適当にk個に分けたデータの平均値を取って、その値に近いものを一つのクラスタにまとめるのでこのような名前が付けられてい(るのではないかとと思い)ます。
k平均法については以下のサイトを見ていただければどのようなものか直感的に理解できると思います。

http://d.hatena.ne.jp/nitoyon/20090409/kmeans_visualise

このような動作をするコードをPythonで書いてみると、こんな感じになりました。


import random

class Cluster(list):
    def average(self):
        try:
            return float(sum(self)) / len(self)
        except ZeroDivisionError:
            return float('inf')

    def __repr__(self):
        return 'Cluster(%s) %s' % (str(self.average()), list.__repr__(self))

def distance(candidate, cluster):
    if len(cluster) == 0:
        return float('inf')
    return abs(candidate - cluster.average())
 
def k_mean(L, num_cluster, cluster=Cluster, distance=distance):
    clusters = [cluster() for x in range(num_cluster)]
    L_ = L[:]
    while len(L_) > 0:
        for i in clusters:
            if len(L_) == 0: break
            i.append(L_.pop(random.randint(0, len(L_)-1)))

    for c in clusters:
        print c
    raw_input()

    before = []
    while clusters != before:
        before = clusters
        clusters = [cluster() for x in range(num_cluster)]
        for i in L:
            distances = [distance(i, c) for c in before]
            distances = zip(distances, clusters)
            distances.sort(lambda x, y: cmp(x[0], y[0]))
            distances[0][1].append(i)
        print '\n\n'
        print '------------------------------------------------------\n\n'
        for c in clusters:
            print c
        print '\n\n------------------------------------------------------'
        raw_input()
    return clusters
        

k_means関数を呼ぶと、Enterキーを押すごとにクラスタ分けのステップが一つずつ進んでいきます。
以下はこの関数の動作のサンプルです。

>>> import random
>>> L = [random.randint(1,1000) for x in range(100)]
>>> kmean.k_mean(L, 10) Cluster(390.6) [679, 44, 360, 7, 933, 778, 450, 413, 68, 174]
Cluster(431.5) [455, 988, 929, 421, 124, 295, 303, 76, 184, 540]
Cluster(331.4) [905, 63, 23, 48, 13, 534, 762, 102, 266, 598]
Cluster(431.7) [250, 411, 44, 493, 203, 962, 447, 405, 400, 702]
Cluster(514.9) [794, 636, 170, 525, 863, 343, 576, 185, 972, 85]
Cluster(556.5) [714, 763, 491, 403, 150, 822, 471, 686, 469, 596]
Cluster(408.7) [440, 892, 214, 284, 726, 146, 499, 598, 264, 24]
Cluster(460.1) [323, 822, 313, 855, 760, 207, 342, 478, 459, 42]
Cluster(239.4) [117, 23, 60, 94, 82, 952, 32, 10, 692, 332]
Cluster(471.5) [515, 585, 676, 32, 7, 749, 525, 341, 667, 618]




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


Cluster(inf) []
Cluster(421.0) [421]
Cluster(328.0) [303, 332, 323, 295, 343, 313, 342, 360, 341]
Cluster(440.0) [440]
Cluster(519.6) [525, 515, 499, 534, 525]
Cluster(758.529411765) [598, 679, 596, 822, 933, 972, 760, 892, 714, 988, 794, 763, 778, 676, 855, 726, 762, 636, 540, 576, 598, 686, 618, 952, 585, 702, 749, 822, 905, 667, 863, 929, 692, 962]
Cluster(406.4) [400, 411, 413, 405, 403]
Cluster(452.75) [450, 447, 455, 459]
Cluster(108.805555556) [207, 42, 150, 266, 44, 203, 85, 250, 60, 44, 82, 174, 94, 102, 117, 214, 10, 23, 7, 68, 185, 48, 32, 124, 32, 184, 24, 13, 170, 63, 284, 264, 146, 7, 76, 23]
Cluster(480.4) [493, 478, 469, 471, 491]


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




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


Cluster(inf) []
Cluster(421.0) [421]
Cluster(308.923076923) [303, 266, 250, 332, 323, 295, 343, 313, 284, 264, 342, 360, 341]
Cluster(440.0) [440]
Cluster(570.5) [598, 525, 596, 515, 636, 540, 576, 534, 598, 525, 618, 585]
Cluster(809.346153846) [679, 822, 933, 972, 760, 892, 714, 988, 794, 763, 778, 676, 855, 726, 762, 686, 952, 702, 749, 822, 905, 667, 863, 929, 692, 962]
Cluster(406.4) [400, 411, 413, 405, 403]
Cluster(452.75) [450, 447, 455, 459]
Cluster(89.15625) [207, 42, 150, 44, 203, 85, 60, 44, 82, 174, 94, 102, 117, 214, 10, 23, 7, 68, 185, 48, 32, 124, 32, 184, 24, 13, 170, 63, 146, 7, 76, 23]
Cluster(483.5) [493, 478, 469, 499, 471, 491]


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

(略)

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


Cluster(inf) []
Cluster(401.857142857) [421, 400, 411, 413, 405, 360, 403]
Cluster(170.363636364) [207, 150, 203, 174, 117, 214, 185, 124, 184, 170, 146]
Cluster(458.625) [478, 469, 450, 447, 440, 471, 455, 459]
Cluster(724.857142857) [679, 760, 714, 794, 763, 778, 676, 726, 762, 686, 702, 749, 667, 692]
Cluster(907.916666667) [822, 933, 972, 892, 988, 855, 952, 822, 905, 863, 929, 962]
Cluster(304.666666667) [303, 266, 250, 332, 323, 295, 343, 313, 284, 264, 342, 341]
Cluster(515.25) [493, 525, 515, 499, 540, 534, 525, 491]
Cluster(46.619047619) [42, 44, 85, 60, 44, 82, 94, 102, 10, 23, 7, 68, 48, 32, 32, 24, 13, 63, 7, 76, 23]
Cluster(601.0) [598, 596, 636, 576, 598, 618, 585]


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




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


Cluster(inf) []
Cluster(401.857142857) [421, 400, 411, 413, 405, 360, 403]
Cluster(170.363636364) [207, 150, 203, 174, 117, 214, 185, 124, 184, 170, 146]
Cluster(458.625) [478, 469, 450, 447, 440, 471, 455, 459]
Cluster(724.857142857) [679, 760, 714, 794, 763, 778, 676, 726, 762, 686, 702, 749, 667, 692]
Cluster(907.916666667) [822, 933, 972, 892, 988, 855, 952, 822, 905, 863, 929, 962]
Cluster(304.666666667) [303, 266, 250, 332, 323, 295, 343, 313, 284, 264, 342, 341]
Cluster(515.25) [493, 525, 515, 499, 540, 534, 525, 491]
Cluster(46.619047619) [42, 44, 85, 60, 44, 82, 94, 102, 10, 23, 7, 68, 48, 32, 32, 24, 13, 63, 7, 76, 23]
Cluster(601.0) [598, 596, 636, 576, 598, 618, 585]


------------------------------------------------------
こんな感じにじわじわと近い数字同士が集まっていきます。
これを使って何か作れたらいいなー

| Python | 23:17 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

evervimに俺得機能を追加してみた

evervimという、vimからevernoteのノートを編集できるプラグインがあります。
しばらくの間このプラグインを使っていたのですが、自分はvimからはメモ程度のノートを書くくらいで、既に書いたノートの編集などは全くしないことがわかりました。
そこで、思いついたことを即座にメモする機能に特化した機能をevervimに追加したプラグインを作ってみました。

DRascal/evervim - GitHub

このプラグインにはEvervimInstantNoteというコマンドが追加されています。このコマンドを実行すると、次のように新しいバッファが作成され、保存時には自動的にevernoteに投稿されます。

20110930-evervim-001.png


ここまでは通常のevervimと同様ですが、このコマンドではXMLタグをほとんど気にする必要はありません。「<>」は自動的に&lt;&gt;に変換され、行末には<br />が追加されます。
ですので、凝った装飾がしたい場合は元のevervimのコマンドを実行したほうが良いでしょう。その場合は、通常と同様EvervimCreateNoteコマンドを実行してください。

| インストール&設定 | 22:01 | comments:0 | trackbacks:0 | TOP↑

| PAGE-SELECT | NEXT