mots quotidiens.
Daichi Mochihashi (持橋大地) daichi <at> ism.ac.jp by hns, version 2.10-pl1.

先月 2008年09月 来月
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

2008年09月02日(火) [n年日記]

#1 SVM 2008終了

SVM 2008 お疲れ様でした。今回はわりと穏やかだったような気がします。
鈴木さんの50ページ以上ある最適化のスライドにみんな圧倒されていて, それに比べると, 僕のスライドは比較的マイルドだったかもしれません。(<本当か?)

この内容はサークルKの今度の第4回でも話す予定ですが, 内輪向けの内容を削除したもの を置いておきます。


2008年09月17日(水) [n年日記]

#1 wchar_t in C++

C++で wstring を使って2バイト文字と1バイト文字を統一的に扱うには, mbstowcs(3) を使って const char * から wchar_t * に変換して, wstring に 格納するのが普通なのだと思う。
さらに iconv(3) で明示的にコード変換をする手もあるが, そこはロケールにお任せ することにして, wstring には EUC がそのまま入っているのだと思っていた。
..ところが, wchar_t「あ」の中身を表示してみると, A4A2ではなく, 42 30という 謎のコードが。泉谷君に相談して二人で調べてみると, どうも wchar_t の中身は いつの間にかUTF-16になっているらしい。(!) 検索してもそんな話は全然ないし, mbstowcs(3) の中にも書いていないのですが, ロケールは入力コードを指定するために使われるのであって, 内部的には変換されて UTF-16で持っていることがわかった。
手元の環境では sizeof(wchar_t) = 4 だが, Unicodeのテーブル を見ると「あ」= 0x3042 で, リトルエンディアンなので「あ」の中身は
42 30 0 0
となっている模様。 正統的には, ロケールに従って元の文字コードに戻して文字クラスを判別するのかも しれないが, そんなの遅くてやっていられないので, 以下のようなコードを地道に 書くことに。
#include <endian.h>

#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ubyte(w) (*((char *)&(w)+1))
#define lbyte(w) (*((char *)&(w)))
#else
#define ubyte(w) (*((char *)&(w)))
#define lbyte(w) (*((char *)&(w)+1))
#endif

wtype_t wtype (wchar_t w)
{
	unsigned char c1 = ubyte(w), c2 = lbyte(w);
	if (0x4E <= c1 && c1 <= 0x9F)
		return ZEN_KANJI;
	..
}
wstring の中身が(普通の方法では)UTF-16というのはあまり聞かない話 なので, (専門の人には知られた話かもしれませんが)ちょっと書いてみました。 というか iswctype(3) が荒っぽすぎるので, 自分で文字クラスの関数を書かないと いけないというのはどうよ, みたいな気が少ししたりして。。
# ちなみに通常の自然言語処理では, 単語を整数に直して後の処理をすることが多い ので, こういうことを心配する場合は普通はあまり多くない, と思います。

#2 -

おまけ。 上のコードをデバッグする時に,
if (t == LATIN_CNTL)
	return "LATIN_CNTL";
if (t == LATIN_SPACE)
	return "LATIN_SPACE";
....
のようなコードを延々と書く必要があって, 何とかならないものかと思っていた。 (今回に限った話ではなく, 前にも同じように思ったことがあった。)
そういえば, cppに関連するマニアックな方法があったような..と思って K&Rの4.11.2節を見てみると, foo(x) をcppで置換する時, #x とするとxがクオート された文字列になって "x" となるらしい。(xは呼び出したときの文字列に置換される。)
ということで, 上のコードは
#define inspect_type(t,type) { if (t == type) return #type; }
inspect_type(t, LATIN_CNTL);
inspect_type(t, LATIN_SPACE);
...
と書いておくと, cppが置換して上と同じコードにしてくれる。(g++ -E で見ると わかる。) ブラボー。初めて使った機能でした。

ちなみに, これは「変数の名前」を"文字列"=データに変換できるということなので, かなり面白い。たとえば,

#define varexec(v) ((void(*)(void))#v)()
のようなマクロを定義しておくと, 変数vの名前を文字列にして, それを関数だと 思って実行することができるはず。だから例えば, 原理的には ASCIIで hello world のような感じで
#define varexec(v)      ((void(*)(void))#v)()
int
main (int argc, char *argv[])
{
	int PTXHHHH0Z_18RVX75ow = -1;	/* 中身は何でもよい */
	varexec(PTXHHHH0Z_18RVX75ow);
	/* = ((void(*)(void))"PTXHHHH0Z_18RVX75ow")(); が実行される */
}
とできるということ(!)。 *1
通常, プログラミング言語では変数は値だけが問題で, 名前は実行には完全に無関係 というナイーブすぎるソシュール主義があるわけですが(注: 前に書いた文章 ), それがここでは完全に逆転していて, 「変数は名前だけが問題で, 中身は何でもよい」 ことになっている。イカス! :-) :-)
*1: 問題は, C言語で許される文字だけで(例えばx86の)機械語としても有効な"名前" をつけるのが難しいかも知れない, ということだと思います。
なお, ((void(*)(void))__FILE__)(); とすると, "ファイル名プログラミング" ができます ("PTXHHHH0Z_18RVX75ow" というファイルにこの1行を書いておく)。この場合は文字の 制限はあまりなさそうです。


2 days displayed.
タイトル一覧
カテゴリ分類
 なかのひと
Powered by hns-2.10-pl1, HyperNikkiSystem Project