Boost使って快適なC++

昨日のC++の記事は少し誤解があった。
実はC++ではオブジェクトが破棄されるときデストラクタというのが実行される。
これによりメモリなどを解放することになる。
それで、Hoge a=Hoge(100);などして作ったオブジェクトは、
そのローカル変数aが使われなくなった時点でデストラクタが呼び出され破棄される。
一方Hoge* b=new Hoge(100);などして動的にメモリを確保して作成したオブジェクトは、
自動では破棄されず、delete b;する必要があると。すっかり忘れてた。
というわけでローカル変数にのみ使う場合はnewで確保しない方がいいですね。
そちらの方が安全と。C#のusing構文のような機能が自動でついているということです。
しかしオブジェクトを作ったところで破棄しない場合はnewで確保するべき。


その上でSTLライブラリの話をしようと思う。
STLは動的配列やらなんやらとにかくデータを投げ込むコンテナやらを提供するライブラリ。
現在はC++の標準ライブラリとなってて、空気のように使われます。
配列ほど高速じゃないとは思うけど、大きさの定めなく配列を作れるので便利かなと。

#include 
#include
#include
class Doing{
public:
void operator()(int cur){
std::cout << cur*100 << std::endl;
}
};
int main(){
std::vector list;
list.push_back(100);
list.push_back(20);
list.push_back(5);
for(std::vector::iterator cur=list.begin(); cur std::cout << *cur << std::endl;
}
std::for_each(list.begin(),list.end(),Doing());
return 0;
}

使い方は、#include として、std::vector(Tはデータの型)のオブジェクトを作るだけ。
push_backメソッドで追加していく。
それでlist[2]などして要素は読めるし、sizeメソッドでオブジェクトのデータ数も読めるのですが…
繰り返し操作にはイテレータが使われるのが普通です。
list.begin()で初めの要素を指すイテレータを得て、++curで勧めて、list.end()に満たないうちは進むと。
++curですが、僕に取っては慣れない書き方なのだが、C++では普通++curのように書きます。
というのもcur++の場合オブジェクトを複製する必要があるらしい。++curの場合それが不要になる。
C++なのに++cと使うことの方が多いわけです。Cではc++と書くのが普通でしたけど。
もっともC++でもint型などはオブジェクトの複製なんて気にすることではなくて、c++のような表記でも問題ない。
まぁこれが1つの方法ですが、もう1つstd::for_each関数を使う方法があります。#include して使う。
それで引数ですが、最初の要素を指すイテレータ、終わりを指すイテレータ、それと関数オブジェクトなんですね。
関数オブジェクトってなんじゃという話ですが、もっともシンプルなのが上に用意したDoingクラスですね。
()演算子をオーバーロードしてますけど、これは関数呼び出し演算子と言います。
これをオーバーロードすれば、Doingクラスのインスタンスをfoo()のように関数ポインタのように取り扱えると。
他にも関数オブジェクトはあるけど、これがもっともわかりやすい。


しかしながらいちいち関数オブジェクト作るのめんどくさい。
それでいろいろ調べてたのだが、いいものがあった。Boostですね。
Let’s Boostが非常に参考になります。ここのインストール方法を見てインストールしましょう。
ヘッダーファイルなどの固まりをダウンロードして展開。
僕はこのフォルダをC:\borland\bcc55\boostとすることにした。なんか変な場所だが好きなところに置けばいいんです。
それでBinのbcc32.cfgの-Iの””の中に;C:\Borland\bcc55\boostを書き足す。
これでBoostが使えます。
さて、このLet’s Boostの関数型プログラミングのところのlambdaの説明を読むと、
簡単に関数オブジェクトが作れることがわかります。ありがたいですね。
#include を追加して、

  using namespace boost::lambda;
std::for_each(list.begin(),list.end(), std::cout << _1*100 << "\n" );

最後にstd::endlを使うとうまく行きませんね。最後は文字列で終わるとよさそう。
どうもBorland C++ Compiler 5.5はコンパイラの限界でこういう問題が起きるそう。
というわけでVisual Studioについてきた、Microsoft製のコンパイラを使おう。clですね。
C:\Program Files\Microsoft Visual Studio 8\Common7\Toolsのvsvars32.batで、
@set INCLUDEの行の最初にC:\Borland\bcc55\boost;を書き足しておきましょう。
それでVisual Studioコマンドプロンプトでclを使うと、うまくコンパイルできて、実行できる。
さらにはこんなこともできる。

  int x=0;
std::for_each(list.begin(),list.end(), x+=_1 );
std::cout << x << std::endl;

なんでもないように見えますがxというのはローカル変数ですね。
作られた関数オブジェクトはこのローカル変数のxをいじることができると。
これは結構すごいことなんですよ。これを平然とやってのけるのはすばらしいですね。


なお、foreach自体は他にも実現方法があります。
というのはBOOST_FOREACHというマクロですね。#include を追加して使います。

  BOOST_FOREACH( int &cur,list){
x+=cur;
}

STLのオブジェクトの他に、静的に確保した配列も使えます。
ただしマクロなので、所々問題はありますが。たとえば受ける変数の型名に,が入ってたらだめだとか。
しかしなかなかおもしろいですね。
C++の足りない部分を補えるかも知れない。
C++の演算子オーバーロードとかテンプレートが強力すぎて実現できたことですから、
実は足りないことではなかったのかも知れませんけど。

言わないのにコンストラクタが走るC++

C++をいろいろ調べているのだがわけがわからない。
なんというか複雑すぎて理解に苦しむところが多い。


まぁとりあえず練習にこんなクラスを作ってみた。

#include 
class Hoge{
private:
int _x;
public:
Hoge(){
std::cout << "Call Constructor(1)" << std::endl;
}
Hoge(int x){
std::cout << "Call Constructor(2)" << std::endl;
this->_x=x;
}
Hoge(const Hoge &other){
std::cout << "Call Constructor(copy)" << std::endl;
this->_x=other._x;
}
int GetX(){
return this->_x;
}
void SetX(int value){
this->_x=value;
}
};
int main(){
Hoge a;
a=Hoge(100);
Hoge b=a;
b.SetX(200);
std::cout << a.GetX() << std::endl;
std::cout << b.GetX() << std::endl;
return 0;
}

まずC++を初めて、まず戸惑うのはstd::coutにシフト演算子で表示したいものを投げ込むことだな。
シフト演算子の使い方としては最悪の部類に入ると思いますよ。
だって本来はシフト演算子って、整数をビットシフトするのに使うわけですからね。
全く意味が違うのに演算子のオーバーロードでこうしてしまうのは明らかにおかしな話です。
C++では演算子のオーバーロードは多用されていますが、あまりに下品すぎると評判で、
JavaやC#では演算子のオーバーロードは慎まれる傾向にありますね。C++を反面教師としたのだろうか。
まぁしかし演算子のオーバーロードで足りない機能を補えるのも確かなので意味を崩さない程度に利用しましょう。


さて、コンストラクタですが、引数無しのコンストラクタ、引数を取るコンストラクタ、const Hoge &otherを引数に取るコピーコンストラクタを用意した。
しかし引数のconst Hoge &othertってなんだよってまず突っ込みたくなりますね。
引数のところに&とつけるのはC#で言うrefのようなものです。参照渡しということですね。
しかし参照渡しなのにconstである。constは値を変更しないという意味。
すなわち読み取り専用の参照渡しということ。しかしそれならポインタで渡せよという気にもなる。
しかしコピーコンストラクタはこう書くと決まっているのだからしょうがない。
コンストラクタが呼ばれたらそれをわかりやすく画面に表示することとした。\
あとGetXとSetXというメソッドを用意した。それで実験をしてみた。
まずHoge a;と宣言する。この時点でCall Constructor(1)と出るから、引数無しのコンストラクタが呼ばれた。
別に呼んでいらんのだが。a=Hoge(100);と新しくインスタンスを作るから。ここでCall Constructor(2)と出る。
その次にHoge b=a;と宣言すると、ここではCall Constructor(copy)と出るからコピーコンストラクタが呼ばれる。
その証拠にbにSetXで200をセットしてもaは前の100のままであると。


じゃあ、と少し変えてみる。

int main(){
Hoge a=Hoge(100);
Hoge b;
b=a;
b.SetX(200);
std::cout << a.GetX() << std::endl;
std::cout << b.GetX() << std::endl; return 0;
}

さて動かすと、まずHoge a=Hoge(100);でCall Constructor(2)と出てくる。これは予想通りですね。
次にHoge b;で、やはりさっきのHoge a;同様、Call Constructor(1)が出てくる。
コピーコンストラクタは呼ばれてないからbにSetXで200をセットすると…aは100、bは200…あれさっきと一緒だ。
というのも実は代入演算子なんてやつが裏で動いているらしい。
そいつがせっせとコピーしていると。

    Hoge& operator=(const Hoge &other){
std::cout << "Call Operator=" << std::endl;
this->_x=other._x;
return *this;
}

これをクラスの定義のpublic:以降に追加してみると、b=a;のところでCall Operator=が出てくる。
しかしこれはC#とはかなり使い勝手が違うよな。
C#では参照型は宣言しても中身はnullだし、代入しても参照を代入するだけだし。
コピーも何もしないんですけどね。C++はコピーとかやってくれる。しかしそれはお節介というものである。


というわけで普通はオブジェクトをポインタでいじるんですね。

int main(){
Hoge *a=new Hoge(100);
Hoge *b=a;
b->SetX(200);
std::cout << a->GetX() << std::endl;
std::cout << b->GetX() << std::endl; return 0;
}

とにかく変数を宣言するときに*つければポインタ型になりますからね。
それでnewでインスタンスを作ればいいと。
そうすればb=aとかしても、実体はコピーされず、参照だけコピーされる。
それで、ポインタで扱うときは、メンバはアロー演算子で参照する。
さっきthis->_xとか書いたけど、thisは自分自身のポインタだそうだ。
これで実行すると、コンストラクタはnew Hoge(100)でCall Constructor(2)と出るだけ。
bにSetXで200をセットすると、aもbも200になっている。


これがC#やらC++/CLIでの扱いと同じような扱いです。
こちらの扱いを専ら使っていくことにしようと思います。
しかしあんなコンストラクタをやたら呼び出すやり方はなんで考えられたんだろ?
と考えてみたのですが、多分構造体の動作に合わせたんだと思います。
構造体は普通に代入すると中身をがばっとコピーするんですね。
なのであまりに大きな構造体はポインタで取り扱いましょうという話になっています。
まぁそれと動作をあわせて、必要に応じてポインタで取り扱うか、コンストラクタを呼びまくるか選んでくれということでしょう。
なら僕はポインタで扱う方を選びましょうと考えるだけです。
さて、いろいろ試していこう。

毎年ある検尿について考える

危うく今日の日記を書き忘れるところだった。
というのも別のBlogの記事をガリガリ書いていたからですね。
あー、忘れたら連続記録が切れてしまうじゃないですか。


そういえば、明日は検尿の回収日なのですが、検尿ねぇ。
尿を調べるとわかることが多いから調べるわけですね。
もっとも今まで何にも言われたことないので、何がわかるのかはよくわかりませんけど。
しかし体の状態をよく表すものではあるそうです。
いやおもしろいですね。


そこでそれを持って行かなくてはならないのでキットが配られます。
コップと試験管です。まぁコップはよくある折りたためるコップですね。
とりあえずここに入れて、これを移し替えて持って行くわけだ。
それで試験管に移し替えろと言われるわけである。
プラスチック製の試験管なんですけどね。一体なんなんだろ?
小学校・中学校の頃は、醤油が入っててもおかしくないような、容器でした。
これの規定の線まで入れるのは結構難しいんですね。
というのも空気をかなり抜いて吸い込まさないといけないから。
まぁこんなのも何年も毎年やってれば慣れますけど。
それに対して試験管の方は、流し込むだけです。こぼさなければ大丈夫です。
そういう意味では楽ですが、見た目がねぇ…


これを教室で集めるわけですが、試験管だから試験管立てに立てるわけだ。
まぁひどい光景ですね。しかも回収時間の加減で昼頃まで置きっぱなしだったりします。
そう考えると、中学校のとき、その入れ物を入れる袋をもらったわけですが、
この袋が緑色をしているんですね。今思えばそれは結構いい工夫だなと思ったものです。
袋のまま回収しますから。緑色といってもかなり濃い緑色なのでね。中身はあるかないかしかわからないほどのものです。
まぁそんなわけで明日忘れずに朝一番に回収しないとね。

TOEICという少し過酷なテストを受けてきた

なんか上本町駅の案内用テレビがどんどん交換されていっているらしい。
前、なんか新しい表示装置が地上に上がる階段の下についていたけど、そのための用意か。
CRTで焼き付きがひどかったからね。やっと交換ですか。
西大寺駅とかは液晶ディスプレイで同じような内容を表示させているけれど、
上本町のはどうも表示形式がかなり変わるらしい。もうすでに奈良線の駅についてるやつと一緒ね。
しかしここまで液晶ディスプレイは当然のように使われるようになるとは。安いからかな。


今日はTOEIC IPテストを学校でやるということで行ってきました。
IPは団体特別受験制度の略で、公開テストではなく学校・職場で実施される試験ということ。
テストは2時間ぶっ通しでやります。
長いねと思ったけど、よく考えれば前受けた基本情報技術者試験は午前午後とも2時間半だったからもっと長い。
しかもとっくに終わってるのに途中退出しなかったからな。
しかしながら、この2時間のテストは長いように見えるが実は短い。
問題数は200問ですから。とはいうものの実際はリスニングは流れるのを聞いて答えるしかないから、
実際時間が問題となるのはリーディングでこれは75分で100問ですね。
これが結構きつい。


しかしリスニングセクションも相当難しいです。けどこっちの方がよっぽど簡単。
Part 1が印刷された写真にあう文章は読まれる4つの文章のどれだろうという問題。
すごく簡単。しかしそれでも難しい問題はありますけどね。けどすごく、というのは他の問題がひどいからです。
Part 2が読まれる質問にふさわしい応答を読まれる3つの文章から選ぶ問題。
何も印刷されてないので少し難しい。けど中には消去法で簡単に解けてしまったり。
というのもWhen ~ ?って質問が流れて、Mr.Smith did.って流れたら明らかにおかしいでしょ。
それで解けるものばっかりじゃないけど、それで解けてしまうのもあるから簡単ですね。
Part 3・Part 4は難しい。これは読まれる会話・放送などについて、印刷された3つの質問に4択で答える問題。
何が難しいかというと、3つの質問を読んで流れるのを聞くのが難しい。
3つの質問を読む時間は与えられないんですね。いつ3つの質問を把握しろと。
考える時間はこの3つの質問を印刷してあるのに読んでくれる時間にすればいいと思うんだけどね。
前の問題をちょっと早めに考え終わって読むべきなんだろうけど、そんな時間作るの難しい。
以上リスニング。わりとよかった気がする。


そしてリーディングですが、なんといっても問題数が多い。
Part 5は文が与えられて、その穴を4択で埋める問題。
この問題はまだやさしい。というのもここは名詞だなとかで解けたりするから。
一方で解きようがない問題もある。知らん単語が4つ並んでて解けるか。こういうのは適当に選んで進んでしまうんです。
考え込むとえらい目にあいます。なのでさっさっさと進んでいこう。
Part 6は文章の中に3つ穴があけてあるのを埋める問題。
ちょっと難しい。というかこの辺から解けない問題だらけになってきた。
ここで考え込んでしまってすごい時間を消費して、Part 7でえらい目にあった。
Part 7は文書を読んで、何個かの質問に答える問題。
この中には1つの文書だけの問題と2つの文書の問題があって、
1つの問題のなかには易しい問題も混ざっているのですが、2つの問題はどれも無理。
最後の方は、質問の答えが文章にあるとはおもえなかった。
なんか最後のせいで今回のテスト調子いいとは思えなくなってきた。
なんとか最後の問題までたどり着くことができました。


ちなみに去年も同様のテストがあったのですが、
スコアはListeningが210点、Readingが205点と、思っていたよりはずっといい点数でした。
去年よりは出来た気もしますけど、しかし本当に出来てるかはわからない。
このスコアは正答数とかじゃなくて、なんか秘密の計算方法で求めるらしい。
スコアはどの回の試験でも同じ能力の人なら同じような点数が出るようになってるらしい。
このスコアの意味するところはTOEIC Square[テスト受験や英語学習のサポート]|Step2:TOEICで目標を設定![初心者ガイド]あたりを参考に。
合計470点あればすばらしいですね。
まぁ本当にそれだけの能力があるかどうかはよくわかりませんけどね。
しかし、CPANやらのドキュメントが英語でかかれてることは多いわけですが、
これを読み解いて、はー、なるほどなとか。
辞書を探しながら、PerlBug投げたりというのはできるようになったわけですからね。
以前ならあり得なかったようなことができているわけだから、それなりに良くなったのかなと。
まぁ点数上がってればいいですけどね。それは学校に結果が届くまでのお楽しみと。

人間がなれた中置記法の式を読むコンピュータ

今日から新学期。というか新学年ですね。4年生です。
4年生ともなると専門科目が増えてくるわけですが、そこでこの先何を勉強するかというのを定めないとなと。
しかし焦ってはならない。のんびりいきましょう。


さて、我々は普段数式を1+2+3-4のように書く。
こういう書き方を中置記法というらしい。これの解釈は難しい。
けど()を使わない、どの演算子の優先順序も同じであるならば簡単。

my $x="1+2+3-4";
my @a=split(m|([-+*/])|,$x);
my $x=shift(@a);
while(@a){
my $op=shift(@a);
my $y=shift(@a);
if ($op eq '+'){
$x+=$y;
}elsif($op eq '-'){
$x-=$y;
}elsif($op eq '*'){
$x*=$y;
}elsif($op eq '/'){
$x/=$y;
}
}
print "Answer : $x\n";

基本はこれです。複雑な式でも()を1つの要素で表すことができて、計算順序は()は気にしなくていいようにすればこれでOK。
()で表したものは[‘5′,’+’,’3′]のように配列リファレンスで表して1つの要素とすることにする。
配列リファレンスで表す式は数値か配列リファレンスで表す式、演算子が交互にでてくると。
そういう式を解釈するサブルーチンを用意すれば、$x,$yをshiftで取り出した後投げればいいと。
再帰ですね。


とりあえずこの処理を実現しなくてはならない。
その前に式から(と)と演算子と数値を取り出さなければね。

sub splitinfix{
my @a=split( m|([-()+*/])| ,$_[0]);
chomp $_ for @a;
for(my $i=0;$i<@a;$i++){
splice(@a,$i,1) while($a[$i] eq '');
}
return \@a;
}

これで与えたら切り出して、その配列のリファレンスをくれる。
どうなるのかチェックしにくいからRubyのpをパクったpというサブルーチンを作った。

use Data::Dumper;
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 0;
sub p {
@_=($_) if !@_;
while(1){
my $d=Dumper(shift(@_));
$d=~s/\\x{([0-9a-f]{4})}/chr(hex($1))/eg;
print $d;
last if !@_;
print ',';
}
print "\n";
}
p splitinfix( '(2*4+1*(2+4-1))*(1+1*2)/(1+1)' );

すると[‘(‘,’2′,’*’,’4′,’+’,’1′,’*’,'(‘,’2′,’+’,’4′,’-‘,’1′,’)’,’)’,’*’,'(‘,’1′,’+’,’1′,’*’,’2′,’)’,’/’,'(‘,’1′,’+’,’1′,’)’]が得られる。
これを処理していくわけですが、むちゃくちゃめんどくさい。

sub infix2infix{
my ($from,$l)=@_;
my $i=$from;
for(;$i<@$l;$i++){
if ($l->[$i] eq ')'){
splice(@$l,$i,1);
return bindop(splice(@$l,$from,$i-$from));
}elsif($l->[$i] eq '('){
splice(@$l,$i,1);
my $part=infix2infix($i,$l);
splice(@$l,$i,0,$part);
}
}
return bindop(@$l);
}
sub bindop{
my @r0=@_;
my @r;
for my $ops([qw(+ -)],[qw(* /)]){
@r=();
my @t=();
while(1){
push(@t,shift(@r0));
last if !@r0;
my $op=shift(@r0);
for(@$ops){
if($op eq $_){
push(@r, @t==1?$t[0]:[@t] ,$op);
@t=(); $op=undef; last;
}
}
push(@t,$op) if defined $op;
}
push(@r, @t==1?$t[0]:[@t] );
@r0=@r;
}
return @r==1?$r[0]:[@r];
}
p infix2infix(0,splitinfix( '(2*4+1*(2+4-1))*(1+1*2)/(1+1)' ));

infix2infixで処理しやすい中置記法に変換するわけだ。といっても) か ( が来るまではそのままです。
第一引数は開始の添え字を与える。
(が出てきたら、そこからの分をinfix2infixに投げる。)が出てきたらそこで終わる。
そこから始まる、そこで終わるというのはその区間だけ処理するということ。
これで()の問題はなくなりますが、このままでは演算子の優先順位の問題があるので、
その区間をspliceで切り取って、bindopに投げる。
ここで、まず+と-で分割して、配列リファレンスでグループ化する。(‘1′,’+’,’1′,’*’,’2′)が与えられたら([‘1′],’+’,[‘1′,’*’,’2′])という風にね。
ただ要素が1つならわざわざ配列リファレンスにしないようにしてある。
こうやって処理したら処理しやすいものが得られる。
0からsplitinfixで作ったやつを処理してみる。
すると[[[‘2′,’*’,’4′],’+’,[‘1′,’*’,[‘2′,’+’,’4′,’-‘,’1′]]],’*’,[‘1′,’+’,[‘1′,’*’,’2′]],’/’,[‘1′,’+’,’1′]]というのが得られる。
あとはこれを始めに書いたやつを改良して処理するだけです。


というわけでこれを処理して計算するもの。

sub parseinfix{
my $a=shift;
if(ref $a){
my $x=parseinfix(shift(@$a));
while(@$a){
my $op=shift(@$a);
my $y=parseinfix(shift(@$a));
if ($op eq '+'){
$x+=$y;
}elsif($op eq '-'){
$x-=$y;
}elsif($op eq '*'){
$x*=$y;
}elsif($op eq '/'){
$x/=$y;
}
}
return $x;
}else{
return $a;
}
}
p parseinfix(infix2infix(0,splitinfix( '(2*4+1*(2+4-1))*(1+1*2)/(1+1)' )));
p eval( '(2*4+1*(2+4-1))*(1+1*2)/(1+1)' );

配列リファレンスかどうか判定するのにrefを使います。
refが”ならばそのまま、’ARRAY’ならば、さっき同様の扱いをすると。あとはshiftしたのをparseinfixに投げるかどうかぐらいのものです。
そしてやると結果は19.5となります。それはあっているのかという話ですが、
実はPerlで中置記法を簡単に処理する方法がありまして、evalしてやればいいんです。
結果は19.5なので正解ですね。


ところで、コンピュータにとって処理しやすいのが逆ポーランド記法です。
始めこれを逆ポーランド記法に変換して、計算しようと思っていたのでそのためのサブルーチンを作りました。

sub infix2rpn{
my $a=shift;
if(ref $a){
my @r=();
push(@r,infix2rpn(shift(@$a)));
while(@$a){
my $op=shift(@$a);
push(@r,infix2rpn(shift(@$a)),$op);
}
return @r;
}else{
return $a;
}
}
print join(' ', infix2rpn(infix2infix(0,splitinfix( '(2*4+1*(2+4-1))*(1+1*2)/(1+1)' )))),"\n";

結果をスペースで区切ってやればよくある逆ポーランド記法の表記になりますね。
結果は2 4 * 1 2 4 + 1 – * + 1 1 2 * + * 1 1 + /です。
逆ポーランド記法は前から順番にスタックに積んでいって、*が来たら上2つを取り出して積をスタックに積む、
という風に機械的に計算できるので、コンピュータの世界で大人気です。
.NET Frameworkで動くプログラムもそう書かれているんです。
C#で中置記法で書いた式は逆ポーランド記法に変換されているようなものです。


ちなみに、中置記法をわかりやすくする方法はいろいろあるようです。
木構造にするという方法が一番わかりやすいかもね。
(2*4+1*(2+4-1))*(1+1*2)/(1+1)とあれば、まず(2*4+1*(2+4-1))の枝を作成、
その中で一番優先順位の高い演算子は+だから左右で分けて、2*4の枝と1*(2+4-1)の枝を作成、
という風にやっていくと、式を木構造にできると。
こうなれば上から順番に読んでいくだけと。なるほどそちらの方がおもしろそうだな。
めんどくさい中置記法ですが、
案外うまくコンピュータは解釈しているようです。

Tumblrに貼るのは付箋のような記事

最近ミニブログというのが流行っていると聞く。
Twitterがミニブログだといわれているのはなかなか理解しにくいところだが、
チャットとBlogの中間形態であると言われている。
どういうことかというと、つぶやきを自分のページに掲示するというあたりがブログらしくて、
フォローしている人のつぶやきをタイムラインとして見られて、Replyで返信できるというあたりがチャットであると。
基本は一方通行なんだけど、Replyのおかげで返信ができるというような仕組みです。
ただあまりブログっぽくないのは、140字制限ですね。


Tumblrというこれもまた有名なミニブログがある。
これはそのまま小さいブログと思ってOKです。
まぁとりあえずユーザー登録したら使えます。ログインするとDashboardという画面にいきます。
特に気にせずに記事は上の方にあるボタンをクリックすれば投稿できると。
そのText・Photo・Quote・Link・Chat・Audio・Movieから投稿するものを選ぶと。
人気があるのはPhotoとQuoteですね。
まぁ例えばQuoteなら、選んでQuoteになんか気になったことを書いて、
Sourceに情報源を書いて、必要に応じてハイパーリンク、コメントがあればしょうがないのでSourceの欄に書く。
そしてCreate Postすると。すれば投稿完了。やったね。
実際どんな具合かはxxxxx.tumblr.comを見ればわかるでしょう。
それで表示の設定を右上のCustomizeで行う。あとInfoでタイトルと説明を書く。
必ず変えるべきところはAdvancedでタイムゾーンを指定すること。
あとThemeを選んで配色とか変えたりすればいいかな。


ところでDashboardって何なのかなと思ったのですが、実はFollowした人のTumblelogが表示されるんですね。
そういうわけで誰か探して、右上のFollowボタンをクリックすればフォロー完了。
すればその人の記事はDashBoardで読めるというわけです。
僕はTwitterでの友人とかからやってる人を何人か偶然発見して、それを適当にFollowしている。
ちなみに友人がいなくてもなんかFollowしておく方がよいとかなんとか。
そのための道標なんて山ほどありますよ。


Tumblrのよくわからない文化がReblogというやつですね。
というかTumblrって転載がアホみたいに多いんですよ。
まぁQuoteはわかりますね。発見したことを引用しておくと。
僕はそれだけではあきたらずコメントをつけるようにしてるけど、コメントつけてないのが圧倒的に多い。
大人気のPhotoですが、これもほとんどが転載です。まぁ自作したやつの発表の場になってたりもするのですが。
というのもTumblrはソーシャルブックマークに似ているんですね。
なんか気になる記事があったら貼り付けると。そんなものです。
それを支援するツールだってあります。例えばFirefoxのアドオンのTomblooとかですね。
例えば気になる内容を発見したら、その部分を選択して右クリックしてShare – Quoteを選ぶ。
これだけでその部分の引用の記事が自動で作成されます。恐ろしいですね。
ShareのQuoteを選べば、▼を押して、これを編集したり、コメントを書き足したり出来ます。僕は普段これでやってる。
画像の上でPhotoを選べばその画像について書くことができる。
まぁそういう習慣が広がっていると。
そういうところなんですね。


僕の書く記事はQuoteとTextがメインですね。だって貼るPhotoがない。
TextはPerlとかLinuxの記録がメイン。短く簡単に書けますから。
今までTwitterに流してきたけど、あとで集めるのがめんどくさかったからこちらの方がありがたい。
というかTwitterは流れるでしょ。後で確認しにくいからね。
実際今日書いた記事が今日役に立ちましたね。ありがたいものです。

ApacheとPHPをアップデートするとFastCGIで動かない

昨日、cronで自動でやってるyum updateでこけてた。
なんでだろうと思って手動でやると、TypeError: unsubscriptable object と言って死んでる
原因を調べたところ、yum clean metadataとすればよさそう。(CentOS Bug Tracker #0003467より)
まぁこれでyum updateとやったわけです。


それでいろんなものがアップデートされて、CentOS 5.3に変わったわけです。
これを実感するためには/etc/redhat-releaseを確認すればいいです。
それで何の問題もないなぁと思っていたのですが、実はPHP絡みでちょっと問題がありました。
というのも僕がPHPをFastCGI動作にするために変えた設定が一部飛んでしまったんですね。
とはいっても致命的なまでにダメージを受けたわけじゃないですけど。
多分このときPHPのバージョンを上げたんでしょうね。
それによって設定が一部飛んだと。するとページが真っ白に。
まず/etc/httpd/conf.d/php.confが再度作られたこと。
これはPHPをモジュール動作にさせるための設定などを書くファイルですが、
いらんわと言って、!php.confに改名していたんですね。
多分あれば上書きはされなかったはずなんですよ。というわけでこのファイルを消すでなく空っぽにした。

# cat /dev/null > /etc/httpd/conf.d/php.conf

これでPHPはモジュール動作しなくなりますね。
この状態でrestartすれば…エラーが500 Errorに変わった。
これはログを見ればCGIのsuexecのエラーだった。
今までラッパーファイルを/var/www/html/php-cgiとおいていたのだが、
この親ディレクトリ/var/www/htmlの所有権が変わって、親ディレクトリと所有者が違うと言われたわけだ。
この所有権を変えると直るんですけど…また同じ事があったら困るしなぁ。
というわけで子ディレクトリに動かしておいた。


その後、この記事を書くときにもう1つ問題に気付いた。
実はFastCGIの導入時、セッションのファイルを置いておくディレクトリのパーミッションを変えてあったんですね。
というのはapacheユーザー以外から書けないようになってたから。
しかしこれもその場しのぎの対応だったということになるだろうか。
というわけでphp.iniでこのディレクトリを/tmpにすることにした。

session.save_path = "/tmp"

これで/tmp以下に配置されるようになる。
ちなみにそのファイルは実行ユーザーで作成され、パーミッションは600、というわけで他のユーザーから見えない。
これでとりあえず完了。


とりあえずこれで今度アップデートがあっても安心ですね。
さらに念入りにするためにモジュール動作でPHPを動作させるのいらんわと思って、そんなパッケージは消すことにした。
と思ったらそんなものないらしい。yumにはphp-apacheとかないんですね。
Vineのaptにはphp5-apache2というのを入れて、モジュール動作にできたんですけどね。
phpというパッケージ自体がそういう機能を持っているようだ。
しかしPHP 6までにはFastCGI動作とかに切り替えないとマルチユーザーの環境だとまずいと思うんだよね。
safemodeのことですね。safemodeはPHP 6で廃止されます。
その理由はsafemodeを過信するユーザーが多いかららしい。
その頃には主流が変わっていてほしいわけですが…
まぁFastCGI動作が唯一の方法ではないとは思いますけど、今のところこれが最有力かなと。
以前取り上げてますけどね。
一部のプロバイダではFastCGI動作に変わっているそうですよ。まぁ一部なんですけどね。
まぁそんなわけで、これからもFastCGIで行きましょうという話でした。

マルチスレッドで速い速いソートをする

ところで昨日の記事で最後に書いた、安定なクイックソートですが、例えばこんなの。

sub mysort{
return @_ if(@_<2);
if(@_<=16){
for my $i(1..$#_){
my $c=splice(@_,$i,1);
my $j=$i;
for(;$j>0;$j--){
last if $_[$j-1]<=$c;
}
splice(@_,$j,0,$c);
}
return @_;
}else{
my $p=$_[rand(@_)];
my @s=([],[],[]);
while(@_){
my $c=shift(@_);
push(@{$s[($c <=> $p)+1]},$c);
}
return (mysort(@{$s[0]}),@{$s[1]},mysort(@{$s[2]}));
}
}
@a=mysort(@a);

適当な値を選んで、前から順番に大きいか同じか小さいかに仕分けをすると。
($c <=> $p)+1というのは$cより$pが小さければ0、同じならば1、大きければ1という風になるようにしてあると。
これで仕分けて、小さいグループ・大きいグループをそれぞれクイックソートすると。
このクイックソートは安定ですよ。世の中にはそんなものもあるのです。
案外早いのですが、かかる時間のばらつきがひどいのでどうしたものかなと思っている。


ところでマージソートは並列処理に向くらしい。
というわけでいろいろ実験してたのだが、結局実験に使うことにしたのはC#ですね。
というのもPerlもRubyもマルチスレッドは無理ではないが、そんなに性能がよくない。
どちらも画面が固まってしまうのを防ぐような、そういうマルチスレッドだけなんですね。
それならと久々にLL(軽量プログラミング言語のこと)じゃない言語を使おうかなとか。
そうなりゃC#ですね。今までC#でいろんなものを作ってきたけど、.NET Frameworkの性能はかなりよろしい。
マルチスレッドだってバリバリに使えますね。
それで久しぶりに書き始めたらforeachをこんな風に書いてしまったりした。

foreach(my cur in foo){ }

myじゃなくてintですね。Perlではなんでもかんでもmyでしたからね。
しかしuse strict;していて変数宣言をする習慣があったので、変数宣言しないとかはそうもなかった。
というかuse strict;って変数宣言については結構厳しいですからね。その点ではそうも心配いらないと。
ちなみに今回使ったのはVisual C# 2008 Express、アカデミック版のVisual Studio 2005は持ってるのにね。
けどなんでこれなのかといえば、C# 3.0を使いたかったから。


というわけで作ってみたソースを張ろうかな。

static class SortWorld {
static void Main(string[] args) {
float[] rnd=new float[50000000];
System.Diagnostics.Stopwatch watch=new System.Diagnostics.Stopwatch();
SortWorld.MultiThreadMode=1;
for (int i=0; i Console.WriteLine("Begin MargeSort"); watch.Reset(); watch.Start();
rnd.MargeSortDestroy();
watch.Stop(); Console.WriteLine("Finish MargeSort Time:{0}[ms]", watch.ElapsedMilliseconds);
for (int i=0; i Console.WriteLine("Begin Array.Sort"); watch.Reset(); watch.Start();
Array.Sort(rnd);
watch.Stop(); Console.WriteLine("Finish Array.Sort Time:{0}[ms]", watch.ElapsedMilliseconds);
Console.ReadKey(true);
}
static private Random _ourrnd;
static public int MultiThreadMode;
static SortWorld() {
_ourrnd=new Random();
MultiThreadMode=0;
}
static public T[] MargeSortDestroy(this T[] self, params Comparison[] fs) where T : IComparable {
self._MargeSortDestroy(MultiThreadMode, fs.Length==0?null:fs[0]);
return self;
}
static private void _MargeSortDestroy(this T[] self, int mode, Comparison f) where T : IComparable {
if (self.Length<2) return;
if (self.Length<=10) {
self._InsertSortDestroy(self.Length, f); return;
}
T[] left=new T[self.Length/2];
Array.Copy(self, 0, left, 0, left.Length);
T[] right=new T[self.Length-left.Length];
Array.Copy(self, left.Length, right, 0, right.Length);
if (mode>0) {
System.Threading.ThreadStart ld=() => { left._MargeSortDestroy(mode-1, f); };
System.Threading.Thread lt=new System.Threading.Thread(ld); lt.Start();
System.Threading.ThreadStart rd=() => { right._MargeSortDestroy(mode-1, f); };
System.Threading.Thread rt=new System.Threading.Thread(rd); rt.Start();
lt.Join(); rt.Join();
} else {
left ._MargeSortDestroy(mode, f);
right._MargeSortDestroy(mode, f);
}
int lp=0, rp=0, ap=0;
while (lp int c=(f==null?left[lp].CompareTo(right[rp]):f(left[lp], right[rp]));
if (c>0) self[ap++]=right[rp++];
else self[ap++]=left[lp++];
}
if (lp else Array.Copy(right, rp, self, ap, right.Length-rp);
}
static private void _InsertSortDestroy(this T[] self, int len, Comparison f) where T : IComparable {
for (int i=1; i for (int j=i; j>0; j--) {
if ((f==null?self[j-1].CompareTo(self[j]):f(self[j-1], self[j]))<=0) break;
T tmp=self[j];
self[j]=self[j-1];
self[j-1]=tmp;
}
}
}
}

なぜか長い。Perlのソースコードよりも明らかにかさばるんですね。なんでだろ。
まぁいいや、ポイントは_MargeSortDestroyメソッドですね。
ところでC# 3.0から始まったことだけど、第一引数のところにthisをつけると、拡張メソッドというメソッドにできるんですね。
どういうことかといいますと、Foo(bar)とするべきところを、拡張メソッドならばbar.Foo()とかけると。
それをちょっと使っています。
10個以下の場合は後ろに書いてある_InsertSortDestroyメソッドで挿入ソートでソートしてもらう。
それ以外の場合は左右に分けて、それぞれを再帰的にマージソート、
それで左右をくっつけていくと。それでできあがりと。
ところでいろんなメソッドにやたらDestroyとついてるけど、破壊的メソッドってことね。
元の配列の要素を半分ずつleftとrightにコピーして、これをそれぞれソート、
そしてそのleftとrightの要素を取り出していって、元の配列に上書きしてしまう。
これこそが破壊的である理由。Rubyなら破壊的メソッドには!つけるんだから、それにならったわけ。
それで、ちょっと工夫してあるのがマルチスレッドの活用ですね。
ただ何でもかんでもスレッドに切り分けると重くなるので、leftとrightで並行処理を行うのは、始め1段のみとしました。
デュアルコアのCPUだとこれが一番効率よさそうです。
そのためにmodeという引数を取ってるけど、これは1段だけ並行処理するときは始めに1を与えて、
並行処理させるたびに1減らしていって、0になったら並行処理しなくするということね。
その並行処理ですが、System.Threading.Threadクラスを使ってる。
デリゲートが作りやすいのはC# 3.0のいいところですね。(x,y)=>{ x.foo(y); }のように作れますからね。
それが_MargeSortDestroyメソッド、実際に使うときはMargeSortDestro
yメソッドを使う。
ここでちょっとおもしろい工夫をしてある。
C# 4.0からは省略可能な引数ができるのですが、C# 3.0まではありません、
けど最後の引数をparamsつけて可変長引数にすれば、最後の引数はなくてもいいんですね。
それで省略できるようにしてある。最後の引数は比較用デリゲートですね。(x,y)=>((int)x).CompareTo((int)y)とか与えれば動きますよ。
まぁこんなところです。
それで実行結果ですが5000万個の配列のソートを38秒で行う。かなり速いですね。
これはマルチスレッド化の成果で、そうしなければ60秒ぐらいかかる。
ちなみに標準のSystem.Array.Sortメソッドは16秒でやる。ただしこちらは安定でないソート。


安定なクイックソートをがんばって実装してみたのですが、これが結構困る。
というのも配列を3つに仕分けするためにメモリをすごく食いそうなんですね。
そこでこんな風にして配列を節約することに。
まず元の配列と同じ長さの配列を用意する。そしてこの配列を頭から読み取って、
ある値よりも小さければ元の配列の読み取り済みのスペースに入れる。
大きければ新しく用意した配列に前から入れる。等しければ新しく用意した配列に後ろから入れる。
仕分けが終わったら、等しいグループを小さいグループの後ろに移動する。
そして、元の配列の小さいグループの部分だけと、新しく用意した配列の大きいグループの部分だけをクイックソート。
完了したら新しく用意した配列のその部分を元の配列の後ろに戻す。
というメモリの節約のためにかなり苦しいことをしています。なので読みにくいったらありゃしない。

  static public T[] StableQuickSortDestory(this T[] self, params Comparison[] fs) where T : IComparable {
self._StableQuickSortDestory(self.Length, MultiThreadMode,fs.Length==0?null:fs[0]);
return self;
}
static private void _StableQuickSortDestory(this T[] self, int len, int mode, Comparison f) where T : IComparable {
if (len<2) return;
if (len<=50) {
self._InsertSortDestroy(len, f);
return;
}
T[] buf=new T[len];
T p=self[_ourrnd.Next(len)];
int lp=0, rp=0, cp=buf.Length-1;
for (int sp=0; sp int m=(f==null?p.CompareTo(self[sp]):f(p, self[sp]));
if (m>0) self[lp++]=self[sp];
else if (m==0) buf[cp--]=self[sp];
else buf[rp++]=self[sp];
}
int llen=lp;
for (int i=buf.Length-1; i>cp; i--) self[lp++]=buf[i];
if (mode>0) {
System.Threading.ThreadStart rd=() => {
buf._StableQuickSortDestory(rp, mode-1, f);
Array.Copy(buf, 0, self, lp, rp);
};
System.Threading.Thread rt=new System.Threading.Thread(rd); rt.Start();
System.Threading.ThreadStart ld=() => { self._StableQuickSortDestory(llen, mode-1, f); };
System.Threading.Thread lt=new System.Threading.Thread(ld); lt.Start();
lt.Join(); rt.Join();
} else {
buf._StableQuickSortDestory(rp, mode, f);
Array.Copy(buf, 0, self, lp, rp);
self._StableQuickSortDestory(llen, mode, f);
}
}

クイックソートは数が少ないと本当に調子が悪いので50個以下で挿入ソートに切り替えています。
それでさっきのMainメソッドのMargeSortDestroyをStableQuickSortDestoryにすればいいのですが、
MultiThreadMode=3にセットしといた方がいいですね。
というのもクイックソートは左右の分割が均等でなくなることがよくあります。
そうなると左はとうに処理終わってるのに、右はまだまだということがあります。
なのでスレッド数を多めに用意しておいて、手が空いたら右のを分担してくれと。
そんな感じです。するとCPUはずっと100%で動いてくれます。
これで40秒ぐらいでソートします。実はマージソートと性能はそうも変わらないんですね。
というのもマージソートは並列処理にすると本当に性能が上がるんですけど、
クイックソートはさっき言ったような事情で並列処理がなかなかうまくいかないと。
それでスレッド数を増やすと遅くなってくる。
それとクイックソート一般の問題ですが、ある値の選び方によって、時間がかかりすぎてしまうという問題がある。
安定ソートなクイックソートですが、残念ながらかかる時間は不安定です。
というわけでさっきのマージソートの方がおすすめですね。


いろいろ試していたけど、やっぱりマージソートは安定していいですね。
これはPerlがマージソートに切り替えたのも納得いくことだ。
ところで久しぶりにC#使ってたら、配列自体にはpushもshiftもないと。
だから始めSystem.Collections.Generic.Queueクラスを使ったんですね。
しかしあまりに遅いし、OutOfMemoryException投げるし。これで楽できればなぁという気持ちはあったのですが無理らしい。
というわけで配列をガリガリ操作するプログラムを久々に書きましたね。
やっぱりPerlやらの配列操作関数は偉大ですね。
けどそういうのに対応できない.NET Frameworkの配列は動作が速いですからね。そういう意味ではありがたいかなと。
適材適所ということですが、あまりに巨大なデータを扱うときはひたすら配列を使うのがよさそうです。
そうじゃなければSystem.Collectionの下にある数々のクラスを選んで使っても便利かなと思いますよ。

便利なソートを使いたいよね

イテレータのソートしようと思ってソートについて調べていた。
ソートのアルゴリズムというと世の中にはいろいろあるものです。
最終的にはマージソートを採用したわけですが、なかなか悩ましいものです。
実際に作って調べてみることにした。例によってPerlで書いてある。@aを数字の大小でソートすることを考えている。


誰でも知っている、というとそれはウソだけど、あまりに有名なのがバブルソート。

my @a=(93,18,11,14,36,86,24,89,82,10,31,33,42,3,0,81,40,40,21,56);
for my $i(0..$#a-1){
for my $j($i+1..$#a){
if($a[$i]>$a[$j]){
my $t=$a[$i];
$a[$i]=$a[$j];
$a[$j]=$t;
}
}
}

まぁなんでこれでソートできるんだというのはよくわからないものですが、
とにかく手当たり次第順番を入れ替えていくようなアルゴリズムですね。
というわけでとてつもなく遅いと評判。
入れ替え部分をリスト代入で書いてないのはちょっと遅いから。
ランダムな10000個の要素をバブルソートする実験では、実に5000万回の比較と2261万回の入れ替えをしていた。
所要時間は50.77秒と、嫌になるほど時間がかかる。要素数の2乗に比例する時間がかかると言われている。


これと同じく嫌になるほど遅いのが挿入ソート。こちらの方がわかりやすいかも。

for my $i(1..$#a){
my $c=splice(@a,$i,1);
my $j=$i;
for(;$j>0;$j--){
last if $a[$j-1]<=$c;
}
splice(@a,$j,0,$c);
}

前から要素を引っこ抜いて、その引っこ抜いたところから前に順にチェックして、適当なところに挿入すると。
適当なところというのは、前の要素が自分と同じか小さいところですね。
1,3,4,6とあるところに4を入れるなら、今ある4の前がちょうどいいと。そういうことです。
実はバブルソートよりも少し性能がいいらしく、2525万回の比較で済んでいる。
挿入の回数は9999回だが、挿入は入れ替えよりもめんどくさいですからね。
時間はぐっと短縮されて20.06秒。バブルソートがあまりに遅いのは、多分Perlのコードの実行に時間がかかってるからじゃないかなと。
多分Cで作ったものならばそうも差はないんじゃないかな。


選択ソートってのもあるらしい。小さい順に選んでソートするから選択ソートというらしい。

for my $i(0..$#a-1){
my $min=$i+1;
for my $j($i+2..$#a){
$min=$j if $a[$min]>$a[$j];
}
($a[$i],$a[$min])=($a[$min],$a[$i]);
}

0番目の要素を含む右側の要素で最小の要素と0番目の要素を入れ替えて…
というのを最後までやっていくわけですね。
10000個ソートすると5000万回の比較が必要なのはバブルソートと一緒だけど、9999回の入れ替えで済む。
なので入れ替えが遅いときには使えるらしい。
ただし、このソートにはちょっと問題がある。というのも安定ソートではないんですね。
安定ソートというのは等しい要素があったら、元の並び順と一緒になるソートのこと。
等しいというのは比較すれば大きくも小さくもないという意味ね。全く一緒の要素かは知らない。
例えば、小数の配列が与えられて整数部の大小だけでソートするとき。

@a=(6.58 , 4.59 , 3.71 , 7.48 , 6.18 , 4.89 , 4.67 , 1.55 , 5.60 , 4.49);
for my $i(0..$#a-1){
my $min=$i+1;
for my $j($i+2..$#a){
$min=$j if int($a[$min])>int($a[$j]);
}
($a[$i],$a[$min])=($a[$min],$a[$i]);
}

この@aでは整数部が4である小数が4つある。4.59,4.89,4.67,4.49の順にならんでほしい。
しかし実際はこの結果は4.89,4.59,4.67,4.49のように元とは少々違う並びになってしまう。
なんでかといえば、隣の要素以外と入れ替えを行うから。
僕は安定なソートが大好きなので、安定でないソートは使わないことにしよう。


ここからは頭のいいソート。
いろいろあるんだが、特に有名なマージソートとクイックソートだけ。
他にも、バブルソートの改良のコムソートとかあるんだけどね。
まずマージソートですね。マージソートはPerl 5.8以降では標準で使われているようです。
以前Perl 5.6から使われてるとか書いたような気がするけど、間違っていたようです。
マージソートはクイックソートよりは遅いかも知れないけど、悪くないというわけで評判らしい。

sub msort{
return @_ if(@_==1);
my $m=int(@_/2);
my @a=msort(@_[0..$m-1]);
my @b=msort(@_[$m..$#_]);
my @r=();
while(@a && @b){
if($a[0]<$b[0]){ push(@r,shift(@a)); }
else { push(@r,shift(@b)); }
}
return (@r,@a,@b);
}
@a=msort(@a);

再帰でやりますよ。やり方は簡単で半分に分割して、それぞれをソートする。
そしてそのソートした半分ずつを、頭から小さい方を選んで引っこ抜いていくと。
例えば7,1,5,2,8,6,3,9と並んでたら、半分に割ってソートにかけると。
すると1,2,5,7と3,6,8,9が得られるので、始めの要素同士を比較して小さい1をまず選ぶと。
次に2,5,7と3,6,8,9となって、2が選ばれ、次に5,7と3,6,8,9となって3が選ばれて…
とやっていくと、前のグループが全部選ばれて、後ろのグループの8,9が残ってしまう。
そこまで来れば、今まで並べた分に余りをくっつければ終わり。
最後の気味の悪い(@r,@a,@b)は、@rに@aと@bをくっつけるということが書いてある。
@aか@bは全部無くなってるはずだから、残った方をくっつけるという意味になりますよね。
なんて感じですばらしく高速です。なんと12万回の比較で済みます。所要時間は0.23秒と比べものにならないぐらい速い。
100万個の要素の並び替えも現実的な時間でできてしまった。所要時間は45.86秒、1867万回の比較で済んでいる。
非常に要素数が多ければ有利なソートですね。まぁ少なくても悪くはないと思いますけど。
このソートのいいところは、ただ半分に割ってそれぞれを別々に計算してくっつけるだけなので並列処理に向くそうだ。
なので実際はもっともっと速くできるかもしれない。
そんなに仕組みも難しくないしいいですね。
ただ欠点は、並び替えのためにデータとは別にメモリを食うこと。
まぁ今のコンピュータで気にするところではないですけど。


最後にクイックソート。速いと評判だが、実に難しい。

sub qsort{
return @_ if(@_<2);
my $p=$_[rand(@_)];
my ($l,$r)=(0,$#_);
while(1){
for(;$_[$l]<$p;$l++){}
for(;$_[$r]>$p;$r--){}
last if($l>=$r);
($_[$l],$_[$r])=($_[$r],$_[$l]);
$l++; $r--;
}
qsort(@_[0 ..$l-1]);
qsort(@_[$r+1..$#_]);
return @_;
}
@a=qsort(@a);

実は理屈はそうは難しくないんですよ。適当な値を選んで、それより小さいのと大きいのに分けて、
それぞれでソートするだけです。適当な値は配列中からランダムに選んでる。
問題はその小さいのと大きいのに分けるところです。
ここで賢い方法を考えてやったら上に書いたようになるのだが、これ両端から見ていくのね。
なので安定ソートではありません。
それと問題なのが、適当な値の選び方なんですね。適当な値をいい加減に選ぶとえらいことになります。
だから要素数が少ないときは他のソートを使うと速いしうまくいくと。
というわけでこんな方法で実験してみた。

sub mysort{
return @_ if(@_<2);
return qsort(@_) if(@_>8);
for my $i(1..$#_){
for(my $j=$i;$j>0;$j--){
last if $_[$j-1]<=$_[$j];
($_[$j-1],$_[$j])=($_[$j],$_[$j-1]);
}
}
return @_;
}
sub qsort{
return @_ if(@_<2);
my $p=$_[rand(@_)];
my ($l,$r)=(0,$#_);
while(1){
for(;$_[$l]<$p;$l++){}
for(;$_[$r]>$p;$r--){}
last if($l>=$r);
($_[$l],$_[$r])=($_[$r],$_[$l]);
$l++; $r--;
}
mysort(@_[0 ..$l-1]);
mysort(@_[$r+1..$#_]);
return @_;
}
qsort(@a);

mysortでは8要素以下は挿入ソートでソートしている。
ちなみにこの挿入ソートはspliceを使っていない。まぁこれがよくある例です。
これだと10000個のソートは0.19秒でやる。比較回数は16万回ですね。
挿入ソート併用しない場合0.22秒程度かかってるので、いくらか速くなってるのは確か。
100万個だと、37.86秒で261万回の比較を行っている。
マージソートよりは速いことがわかる。


しかし結局マージソートにしたのは、クイックソートがめんどくさいというのが大きいのだけど、
マージソートは来たデータから順番に処理していけるんですね。
イテレータで順番に読んでいくとき、2つ受け取って並び替えて、2つのブロックが2つできたら、
その2つのブロックをソートしてくっつけて4つのブロック、同様にして4つのブロックができたら8つに…
ということができて楽しいからマージソートにした。
ちなみにクイックソートが安定でないというのはこのような入れ替えで前後に分けた場合であって、
それ以外の方法では安定なソートになることもあります。
そんな方法もまた調べてみようかな。

Unicodeにこだわるからか、うまくいかない

ええ加減散髪に行ってきた。
これでもかってぐらい切ってもらった。
同じ値段でやってもらうのが申し訳ないぐらい切ってもらった。
まぁ先延ばししてきて髪の毛がすごい伸びてやっと散髪にいくというのはひどいですが、
しかしすっきりしたのでこれでよしとしましょう。
そういえば今日はエイプリルフールか。冗談を言う日ではあるけれど、
しかしそんな日になにやら真面目に発表するところもあるわけだしね。
だからエイプリルフールに便乗した行動は、必ずしも冗談じゃないのだよというのは最近思うところですね。


URLで使える文字はRFC3986によれば数字・アルファベット・ハイフン・ピリオド・アンダースコア・チルダらしい。
これ以外の文字は%E5などして表示する必要があると。
PHP使ってるとこの辺は自動的に考えてくれるので、あまり気にしなくていい。
ただ受け取った文字列のエンコーディングはわからないので、内部で使ってるエンコーディングに統一する必要があるが。
しかし受け取るのもUTF-8、使うのもUTF-8なら気にすることはないでしょう。
作るのはurlencode関数でできるそうだ。


Perlでこれをやるには正規表現で置換するのが普通ですね。

my $x='%83R%83%93%83Z%83%93%83g%82%a9%82%e7%89%ce%82%aa%95%ac%82%a2%82%bd';
$x=~s/%([0-9A-Fa-f]{2})/pack('C',hex($1))/eg;
print $x;

ここではuse utf8;の類はしないで、Shift_JISで出力すれば端末で見れることを考える。
有名な方法ですね。
ただ以前pack(‘C’,hex($1))はかなり無駄に見えるからchr(hex($1))と書く方がよいのではというのを見たことがある。
僕もそれには賛成ですね。というわけで以下はそんな風に書きます。
まぁPerlでCGI作るわけでもないのでこれだけなら記事にすることではないのだが、
ただこれが思惑通り行かないこともあるんですね。


それがuse utf8;の類を使ったときですね。

use encoding 'shiftjis';
use Encode;
binmode(STDOUT,':encoding(shiftjis)');
my $x='%e3%83%9e%e3%83%b3%e3%83%9b%e3%83%bc%e3%83%ab%e3%81%8c%e5%90%b9%e3%81%a3%e9%a3%9b%e3%82%93%e3%81%a0';
$x=~s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
print decode('utf8',$x);

use encoding ‘shiftjis’;とエンコーディングがShift_JISであると示す。
そうすると急にうまく行かなくなる。
use utf8;なら問題なくいくことも多いけど、まぁたまにうまくいかないときもある。
実はそうもプログラムは間違ってないんですよ。
このあたりがuse utf8;の難しいところです。


use utf8;の類を宣言すると普通は文字列にUTF-8フラグというのが立つ。
これは文字をUnicodeで表しておくするモードですね。
print ord(‘田’);としたとき、Shift_JISの環境ならば普通は147と出てくる。
というのも’田’は0x93と0x39の2バイトで表される。その1バイト目は0x93、10進数に直すと147となるわけだ。
しかしuse utf8;の類をすると、この結果は30000となる。
このときは田というのは0x7350と記録されているわけだ。その1文字目の0x7350を10進数に直すと30000と。
その違いがかなり厄介なんですね。
というのはこの置換のとき、%e3というのを発見したら、chr(hex(‘e3’))に置き換えるわけだが、
これが厄介で、use utf8;してるとUnicodeの0xE3に置き換えてしまう。


UTF-8フラグ自体はこうやったら外せるんですね。

$x=encode('utf8',$x);

しかしこれで外したところで状況が改善されるわけでもない。
一体どうなっているのだろうか。
やはりこういうことはUTF-8フラグをつけないのがよいのだろうか。

use strict;
use warnings;
use encoding 'shiftjis';
use Encode;
binmode(STDOUT,':encoding(shiftjis)');
my $x;
{
no encoding 'shiftjis';
$x='%e3%83%9e%e3%83%b3%e3%83%9b%e3%83%bc%e3%83%ab%e3%81%8c%e5%90%b9%e3%81%a3%e9%a3%9b%e3%82%93%e3%81%a0';
$x=~s/%([0-9A-Fa-f]{2})/pack('C',hex($1))/eg;
}
print decode('utf8',$x);

とりあえずこうすればうまくいくようになった。
しかしどうしたものかな。全部Unicodeというのも困ったものだ。